WinEvent简介
WinEvent 可以监视所有窗口或特定窗口的窗口事件。目前支持以下事件:显示、创建、关闭、激活、非激活、移动、开始移动、结束移动、最小化、还原、最大化。有关详细信息,请参见库中函数的注释。
该库最新版可在Git Hub上获得。
WinEvent.ahk
,以下是2024年5月的版本:
#Requires AutoHotkey v2/*** The WinEvent class can monitor window events for all windows or specific windows. * Currently the following events are supported: `Show`, `Create`, `Close`, `Active`, `NotActive`, `Move`, * `MoveStart`, `MoveEnd`, `Minimize`, `Restore`, `Maximize`. See comments for the functions for more information.* * All the event initiation methods have the same syntax: * `WinEvent.EventType(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="")`* where Callback is the function that will be called once the event happened, and Count specifies* the maximum amount of callbacks. * The function returns an event hook object that describes the hook (see descriptions down below).* NOTE: if all WinTitle criteria are left empty then any window will match. To match for Last Found* Window, use WinExist() as WinTitle.* * `Callback(eventObj, hWnd, dwmsEventTime)`* `eventObj` : the event hook object describing the hook* `hWnd` : the window handle that triggered the event* `dwmsEventTime`: the `A_TickCount` for when the event happened* * Hook object properties:* `EventHook.EventType`* The name of the event type (Show, Close, etc)* `EventHook.MatchCriteria`* The window matching criteria in array format `[WinTitle, WinText, ExcludeTitle, ExcludeText]`* `EventHook.Callback`* The callback function* `EventHook.Count`* The current count of how many times the callback may be called* `EventHook.Pause(NewState:=1)* Pauses or unpauses the hook. 1 = pause, 0 = unpause, -1 = toggle* `EventHook.IsPaused`* Used to get or set whether the hook is currently active or paused* * Hook object methods:* `EventHook.Stop()`* Stops the event hook* * WinEvent methods (in addition to the event methods):* `WinEvent.Stop(EventType?, WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")`* Stops one or all event hooks.* `WinEvent.Pause(NewState:=1)* Pauses or unpauses all event hooks. 1 = pause, 0 = unpause, -1 = toggle* `WinEvent.IsRegistered(EventType, WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")* Checks whether an event with the specified type and criteria is registered.* `WinEvent.IsEventTypeRegistered(EventType)`* Checks whether any events for a given event type are registered.* * WinEvent properties:* `WinEvent.IsPaused`* Can be used to get or set the paused state of all events. */
class WinEvent {; A curated list of event enumerationsstatic EVENT_OBJECT_CREATE := 0x8000,EVENT_OBJECT_DESTROY := 0x8001,EVENT_OBJECT_SHOW := 0x8002,EVENT_OBJECT_FOCUS := 0x8005,EVENT_OBJECT_LOCATIONCHANGE := 0x800B,EVENT_SYSTEM_MINIMIZESTART := 0x0016,EVENT_SYSTEM_MINIMIZEEND := 0x0017,EVENT_SYSTEM_MOVESIZESTART := 0x000A,EVENT_SYSTEM_MOVESIZEEND := 0x000B,EVENT_SYSTEM_FOREGROUND := 0x0003,EVENT_OBJECT_NAMECHANGE := 0x800C/*** When a window is shown* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Show(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") =>this("Show", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is created, but not necessarily shown* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Create(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("Create", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is destroyed/closed* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Close(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("Close", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is activated/focused* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Active(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("Active", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is inactivated/unfocused* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static NotActive(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("NotActive", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is moved or resized* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Move(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("Move", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is starting to be moved or resized* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static MoveStart(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("MoveStart", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window has been moved or resized* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static MoveEnd(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("MoveEnd", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is minimized* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Minimize(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("Minimize", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is restored* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Restore(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("Restore", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** When a window is maximized* @param {(eventObj, hWnd, dwmsEventTime) => Integer} Callback* - `hWnd` : the window handle that triggered the event* - `dwmsEventTime`: the `A_TickCount` for when the event happened* @param {Number} Count Limits the number of times the callback will be called (eg for a one-time event set `Count` to 1).* @returns {WinEvent} */static Maximize(Callback, WinTitle:="", Count:=-1, WinText:="", ExcludeTitle:="", ExcludeText:="") => this("Maximize", Callback, Count, [WinTitle, WinText, ExcludeTitle, ExcludeText])/*** Stops one or all event hooks* @param EventType The name of the event function (eg Close).* If this isn't specified then all event hooks will be stopped.*/static Stop(EventType?, WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="") {local MatchMap, Hookif !IsSet(EventType) {for EventType, MatchMap in this.__RegisteredEventsfor MatchCriteria, Hook in MatchMapHook.Stop()this.__New()return}if !this.__RegisteredEvents.Has(EventType)returnWinTitle := this.__DeobjectifyWinTitle(WinTitle)for MatchCriteria, EventObj in this.__RegisteredEvents[EventType].Clone()if MatchCriteria[1] = WinTitle && MatchCriteria[2] = WinText && MatchCriteria[3] = ExcludeTitle && MatchCriteria[4] = ExcludeTextEventObj.Stop()}/*** Pauses or unpauses all event hooks. This can also be get/set via the `WinEvent.IsPaused` property. * @param {Integer} NewState 1 = pause, 0 = unpause, -1 = toggle pause state.*/static Pause(NewState := 1) => (this.IsPaused := NewState = -1 ? !this.IsPaused : NewState)/*** Checks whether an event with the specified type and criteria is registered* @param EventType The name of the event function (eg Close)*/static IsRegistered(EventType, WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="") {if !this.__RegisteredEvents.Has(EventType)return 0WinTitle := this.__DeobjectifyWinTitle(WinTitle)for MatchCriteria, EventObj in this.__RegisteredEvents[EventType]if MatchCriteria[1] = WinTitle && MatchCriteria[2] = WinText && MatchCriteria[3] = ExcludeTitle && MatchCriteria[4] = ExcludeTextreturn 1return 0}/*** Checks whether any events for a given event type are registered* @param EventType The name of the event function (eg Close)*/static IsEventTypeRegistered(EventType) => this.__RegisteredEvents.Has(EventType); Stops the event hook, same as if the object was destroyed.Stop() => (this.__Delete(), this.MatchCriteria := "", this.Callback := "")/*** Pauses or unpauses the event hook. This can also be get/set via the `EventHook.IsPaused` property. * @param {Integer} NewState 1 = pause, 0 = unpause, -1 = toggle pause state.*/Pause(NewState := 1) => (this.IsPaused := NewState = -1 ? !this.IsPaused : NewState)class Hook {/*** Sets a new event hook using SetWinEventHook and returns on object describing the hook. * When the object is released, the hook is also released.* @param {(hWinEventHook, event, hwnd, idObject, idChild, idEventThread, dwmsEventTime) => Integer} callbackFunc The function that will be called, which needs to accept 7 arguments.* @param {Integer} [eventMin] Optional: Specifies the event constant for the lowest event value in the range of events that are handled by the hook function. * Default is the lowest possible event value. * - See more about [event constants](https://learn.microsoft.com/en-us/windows/win32/winauto/event-constants)* - [Msaa Events List](Https://Msdn.Microsoft.Com/En-Us/Library/Windows/Desktop/Dd318066(V=Vs.85).Aspx)* - [System-Level And Object-Level Events](Https://Msdn.Microsoft.Com/En-Us/Library/Windows/Desktop/Dd373657(V=Vs.85).Aspx)* - [Console Accessibility](Https://Msdn.Microsoft.Com/En-Us/Library/Ms971319.Aspx)* @param {Integer} [eventMax] Optional: Specifies the event constant for the highest event value in the range of events that are handled by the hook function.* If eventMin is omitted then the default is the highest possible event value.* If eventMin is specified then the default is eventMin.* @param {Integer|String} [winTitle=0] Optional: WinTitle of a certain window to hook to. Default is system-wide hook.* @param {Integer} [PID=0] Optional: process ID of the process for which threads to hook to. Default is system-wide hook.* @param {Integer} [flags=0] Flag values that specify the location of the hook function and of the events to be skipped.* Default is `WINEVENT_OUTOFCONTEXT` = 0. * @returns {WinEventHook} */__New(callbackFunc, eventMin?, eventMax?, winTitle := 0, PID := 0, flags := 0) {if !IsSet(eventMin)eventMin := 0x00000001, eventMax := IsSet(eventMax) ? eventMax : 0x7fffffffelse if !IsSet(eventMax)eventMax := eventMinif !HasMethod(callbackFunc)throw ValueError("The callbackFunc argument must be a function", -1)this.callback := callbackFunc, this.winTitle := winTitle, this.flags := flags, this.eventMin := eventMin, this.eventMax := eventMax, this.threadId := 0if winTitle != 0 {if !(this.winTitle := WinExist(winTitle))throw TargetError("Window not found", -1)this.threadId := DllCall("GetWindowThreadProcessId", "Int", this.winTitle, "UInt*", &PID)}this.pCallback := CallbackCreate(callbackFunc, "C", 7), this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback, "UInt", this.PID := PID, "UInt", this.threadId, "UInt", flags)}__Delete() {DllCall("UnhookWinEvent", "Ptr", this.hHook), CallbackFree(this.pCallback)}}; ONLY INTERNAL METHODS AHEADstatic __RequiredHooks := Map("Show", [this.EVENT_OBJECT_SHOW], "Create", [this.EVENT_OBJECT_CREATE], "Close", [this.EVENT_OBJECT_CREATE, this.EVENT_OBJECT_NAMECHANGE, this.EVENT_OBJECT_DESTROY], "Active", [this.EVENT_SYSTEM_FOREGROUND], "NotActive", [this.EVENT_SYSTEM_FOREGROUND], "Move", [this.EVENT_OBJECT_LOCATIONCHANGE], "MoveStart", [this.EVENT_SYSTEM_MOVESIZESTART], "MoveEnd", [this.EVENT_SYSTEM_MOVESIZEEND], "Minimize", [this.EVENT_SYSTEM_MINIMIZESTART], "Maximize", [this.EVENT_OBJECT_LOCATIONCHANGE]); Internal variables: keep track of registered events (the match criteria) and registered window hooksstatic __RegisteredEvents := Map(), __Hooks := Map(), IsPaused := 0static __New() {this.Prototype.__WinEvent := thisthis.__RegisteredEvents := Map(), this.__RegisteredEvents.CaseSense := 0this.__Hooks := Map(), this.__Hooks.CaseSense := 0}; Extracts hWnd property from an object-type WinTitlestatic __DeobjectifyWinTitle(WinTitle) => (IsObject(WinTitle) ? WinTitle.hWnd : WinTitle); Activates all necessary window hooks for a given WinEvent typestatic __AddRequiredHooks(EventType) {local _, Hookfor _, Hook in this.__RequiredHooks[EventType]this.__AddHook(Hook)}; Removes (and/or decreases ref count) all necessary window hooks for a given WinEvent typestatic __RemoveRequiredHooks(EventType) {local _, Hookfor _, Hook in this.__RequiredHooks[EventType]this.__RemoveHook(Hook)}; Internal use: activates a new hook if not already active and increases its reference countstatic __AddHook(Hook) {if !this.__Hooks.Has(Hook)this.__Hooks[Hook] := this.Hook(this.__HandleWinEvent.Bind(this), Hook), this.__Hooks[Hook].RefCount := 0this.__Hooks[Hook].RefCount++}; Internal use: decreases a hooks reference count and removes it if it falls to 0static __RemoveHook(Hook) {this.__Hooks[Hook].RefCount--if !this.__Hooks[Hook].RefCountthis.__Hooks.Delete(Hook)}; Internal use: creates a new WinEvent object, which contains info about the registered event; such as the type, callback function, match criteria etc.__New(EventType, Callback, Count, MatchCriteria) {__WinEvent := this.__WinEvent, this.EventType := EventType, this.MatchCriteria := MatchCriteria, this.Callback := Callback, this.Count := Count, this.IsPaused := 0MatchCriteria[1] := __WinEvent.__DeobjectifyWinTitle(MatchCriteria[1])this.MatchCriteria.IsBlank := (MatchCriteria[1] == "" && MatchCriteria[2] == "" && MatchCriteria[3] == "" && MatchCriteria[4] == "")if InStr(MatchCriteria[1], "ahk_id")this.MatchCriteria.ahk_id := (RegExMatch(MatchCriteria[1], "ahk_id\s*([^\s]+)", &match) ? (match[1] ? Integer(match[1]) : 0) : 0)else if IsInteger(MatchCriteria[1])this.MatchCriteria.ahk_id := MatchCriteria[1]elsethis.MatchCriteria.ahk_id := 0if EventType = "Close" {this.__UpdateMatchingWinList()__WinEvent.__UpdateWinList()} else if EventType = "NotActive" {try this.__IsActive := WinActive(MatchCriteria*)catchthis.__IsActive := 0}if !__WinEvent.__RegisteredEvents.Has(EventType)__WinEvent.__RegisteredEvents[EventType] := Map()__WinEvent.__RegisteredEvents[EventType][MatchCriteria] := this__WinEvent.__AddRequiredHooks(EventType)}; Internal use: once a WinEvent object is destroyed, deregister the match criteria and remove ; the hook (if no other WinEvent objects depend on it)__Delete() {if !this.MatchCriteriareturnthis.__WinEvent.__RegisteredEvents[this.EventType].Delete(this.MatchCriteria)this.__WinEvent.__RemoveRequiredHooks(this.EventType)}; Internal use: sets a timer for the callback function (to avoid the thread being Critical; because the HandleWinEvent thread is Critical). Also keeps track of how many times the ; callback has been called.__ActivateCallback(args*) {SetTimer this.Callback.Bind(args*), -1if --this.Count = 0this.Stop()}; Internal use: handles the event called by SetWinEventHook. static __HandleWinEvent(hWinEventHook, event, hwnd, idObject, idChild, idEventThread, dwmsEventTime) {Critical -1static OBJID_WINDOW := 0, INDEXID_CONTAINER := 0, EVENT_OBJECT_CREATE := 0x8000, EVENT_OBJECT_DESTROY := 0x8001, EVENT_OBJECT_SHOW := 0x8002, EVENT_OBJECT_FOCUS := 0x8005, EVENT_OBJECT_LOCATIONCHANGE := 0x800B, EVENT_SYSTEM_MINIMIZESTART := 0x0016, EVENT_SYSTEM_MINIMIZEEND := 0x0017, EVENT_SYSTEM_MOVESIZESTART := 0x000A, EVENT_SYSTEM_MOVESIZEEND := 0x000B, EVENT_SYSTEM_FOREGROUND := 0x0003, EVENT_OBJECT_NAMECHANGE := 0x800C ; These are duplicated here for performance reasonsif this.IsPausedreturnlocal PrevDHW := DetectHiddenWindows(1), HookObj, MatchCriteriaidObject := idObject << 32 >> 32, idChild := idChild << 32 >> 32, event &= 0xFFFFFFFF, idEventThread &= 0xFFFFFFFF, dwmsEventTime &= 0xFFFFFFFF ; convert to INT/UINTif (event = EVENT_OBJECT_DESTROY) {if !this.WinList.Has(hWnd)goto Cleanupfor MatchCriteria, HookObj in this.__RegisteredEvents["Close"] {if !HookObj.IsPaused && HookObj.MatchingWinList.Has(hWnd)HookObj.__ActivateCallback(HookObj, hWnd, dwmsEventTime)HookObj.__UpdateMatchingWinList()}this.__UpdateWinList()goto Cleanup}if (idObject != OBJID_WINDOW || idChild != INDEXID_CONTAINER || !DllCall("IsTopLevelWindow", "ptr", hWnd))goto Cleanupif (event = EVENT_OBJECT_NAMECHANGE || event = EVENT_OBJECT_CREATE) && this.__RegisteredEvents.Has("Close") {for MatchCriteria, HookObj in this.__RegisteredEvents["Close"]HookObj.__UpdateMatchingWinList()if event = EVENT_OBJECT_CREATEthis.__UpdateWinList()}if (event = EVENT_OBJECT_LOCATIONCHANGE && this.__RegisteredEvents.Has("Maximize")) { ; Only handles "Maximize"for MatchCriteria, HookObj in this.__RegisteredEvents["Maximize"] {if !HookObj.IsPaused && (MatchCriteria.IsBlank || (MatchCriteria.ahk_id ? MatchCriteria.ahk_id = hWnd && WinExist(MatchCriteria*) : WinExist(MatchCriteria[1] " ahk_id " hWnd, MatchCriteria[2], MatchCriteria[3], MatchCriteria[4]))) {if WinGetMinMax(hWnd) != 1continueHookObj.__ActivateCallback(HookObj, hWnd, dwmsEventTime)}}} if ((event = EVENT_OBJECT_LOCATIONCHANGE && EventName := "Move")|| (event = EVENT_OBJECT_CREATE && EventName := "Create") || (event = EVENT_OBJECT_SHOW && EventName := "Show")|| (event = EVENT_SYSTEM_MOVESIZESTART && EventName := "MoveStart")|| (event = EVENT_SYSTEM_MOVESIZEEND && EventName := "MoveEnd")|| (event = EVENT_SYSTEM_MINIMIZESTART && EventName := "Minimize")|| (event = EVENT_SYSTEM_MINIMIZEEND && EventName := "Restore")|| (event = EVENT_SYSTEM_FOREGROUND && EventName := "Active")) && this.__RegisteredEvents.Has(EventName) {for MatchCriteria, HookObj in this.__RegisteredEvents[EventName] {if !HookObj.IsPaused && (MatchCriteria.IsBlank || (MatchCriteria.ahk_id ? MatchCriteria.ahk_id = hWnd && WinExist(MatchCriteria*) : WinExist(MatchCriteria[1] " ahk_id " hWnd, MatchCriteria[2], MatchCriteria[3], MatchCriteria[4])))HookObj.__ActivateCallback(HookObj, hWnd, dwmsEventTime)}} if (event = EVENT_SYSTEM_FOREGROUND && this.__RegisteredEvents.Has("NotActive")) {for MatchCriteria, HookObj in this.__RegisteredEvents["NotActive"] {try hWndActive := WinActive(MatchCriteria*)catchhWndActive := 0try if !HookObj.IsPaused && HookObj.__IsActive && !hWndActive {HookObj.__ActivateCallback(HookObj, HookObj.__IsActive, dwmsEventTime)HookObj.__IsActive := 0}if hWndActive = hWndHookObj.__IsActive := hWnd}}Cleanup:DetectHiddenWindows PrevDHWSleep(-1) ; Check the message queue immediately}; Internal use: keeps track of all open windows to only handle top-level windowsstatic __UpdateWinList() {local WinList := WinGetList(), WinListMap := Map(), hWndfor hWnd in WinListWinListMap[hWnd] := 1this.WinList := WinListMap}; Internal use: keeps track of open windows that match the criteria, because matching for name; class etc wouldn't work after the window is already destroyed. __UpdateMatchingWinList() {if !this.MatchCriteriareturnlocal MatchingWinList := WinGetList(this.MatchCriteria*), MatchingWinListMap := Map(), hWndfor hWnd in MatchingWinListMatchingWinListMap[hWnd] := 1this.MatchingWinList := MatchingWinListMap}
}
举几个例子
第一个例子 监测WinEvent.Show事件
监测Notepad窗口被创建事件,以Notepad记事本为例,当探测到Notepad窗口创建时,显示一个ToolTip
提示。
说明,需要将本脚本与WinEvent.ahk
放到同一个目录里进行测试。
#Requires AutoHotkey v2
#include WinEvent.ahk;检测何时创建了Notepad窗口. 按 F1 启动Notepad 来测试.
WinEvent.Show(NotepadCreated, "ahk_class Notepad ahk_exe notepad.exe")
; WinEvent.Show(NotepadCreated, "ahk_exe notepad.exe",1) ;仅仅监控1次。
Persistent()NotepadCreated(hook, hWnd, dwmsEventTime) {ToolTip "Notepad 窗口创建于" dwmsEventTime ", 句柄为" hWnd "`n"SetTimer ToolTip, -3000
}F1::Run("notepad.exe")
第二个例子 监测WinEvent.Close事件
监测Notepad窗口关闭事件。请注意,如果使用"A"
替换掉WinExist("A")
将检测到任何活动窗口的关闭,而不是Notepad窗口。
第3个参数1表示一旦回调函数被调用一次,钩子就会停止。
#Requires AutoHotkey v2
#include WinEvent.ahkRun "notepad.exe"
WinWaitActive "ahk_exe notepad.exe"
; Notepad窗口关闭时,会回调ActiveWindowClosed。
WinEvent.Close(ActiveWindowClosed, WinExist("A"), 1)
Persistent()ActiveWindowClosed(*) {MsgBox "Notepad 窗口关闭了,点击 确定 按钮 退出"ExitApp
}
第三个例子 监测WinEvent.Maximize事件
监测窗口最大化事件,这里没指定特定窗口标识,将监视所有窗口的最大化。
#Requires AutoHotkey v2
#include WinEvent.ahk; 监测所有窗口的最大化事件
WinEvent.Maximize(WindowMaximizedEvent)
Persistent()WindowMaximizedEvent(hook, hWnd, dwmsEventTime) {if MsgBox("一个窗口最大化于 " dwmsEventTime ", 句柄" hWnd "`n`n停止监控?",, 0x4) = "Yes"hook.Stop()
}F1::Run("notepad.exe")
第四个例子 监测WinEvent.Active事件
测WinEvent.Active事件,实现当窗口激活时显示激活窗口的一些信息。
#Requires AutoHotkey v2
#include WinEvent.ahkWinEvent.Active(ActiveWindowChanged)
Persistent()ActiveWindowChanged(hook, hWnd, *) {ToolTip "激活窗口变了! 新窗口信息为: `n" WinGetInfo(hWnd)SetTimer ToolTip, -5000
}/*** Gets info about a window (title, process name, location etc)* @param WinTitle Same as AHK WinTitle* @param {number} Verbose How verbose the output should be (default is 1):* 0: Returns window title, hWnd, class, process name, PID, process path, screen position, min-max info, styles and ex-styles* 1: Additionally returns TransColor, transparency level, text (both hidden and not), statusbar text* 2: Additionally returns ClassNN names for all controls* @param WinText Same as AHK WinText* @param ExcludeTitle Same as AHK ExcludeTitle* @param ExcludeText Same as AHK ExcludeText* @param {string} Separator Linebreak character(s)* @returns {string} The info as a string. * @example MsgBox(WinGetInfo("ahk_exe notepad.exe", 2))*/
WinGetInfo(WinTitle:="", Verbose := 1, WinText:="", ExcludeTitle:="", ExcludeText:="", Separator := "`n") {if !(hWnd := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText))throw TargetError("Target window not found!", -1)out := 'Title: 'try out .= '"' WinGetTitle(hWnd) '"' Separatorcatchout .= "#ERROR" Separatorout .= 'ahk_id ' hWnd Separatorout .= 'ahk_class 'try out .= WinGetClass(hWnd) Separatorcatchout .= "#ERROR" Separatorout .= 'ahk_exe 'try out .= WinGetProcessName(hWnd) Separatorcatchout .= "#ERROR" Separatorout .= 'ahk_pid 'try out .= WinGetPID(hWnd) Separatorcatchout .= "#ERROR" Separatorout .= 'ProcessPath: 'try out .= '"' WinGetProcessPath(hWnd) '"' Separatorcatchout .= "#ERROR" Separatorout .= 'Screen position: 'try { WinGetPos(&X, &Y, &W, &H, hWnd)out .= "x: " X " y: " Y " w: " W " h: " H Separator} catchout .= "#ERROR" Separatorout .= 'MinMax: 'try out .= ((minmax := WinGetMinMax(hWnd)) = 1 ? "maximized" : minmax = -1 ? "minimized" : "normal") Separatorcatchout .= "#ERROR" Separatorstatic Styles := Map("WS_OVERLAPPED", 0x00000000, "WS_POPUP", 0x80000000, "WS_CHILD", 0x40000000, "WS_MINIMIZE", 0x20000000, "WS_VISIBLE", 0x10000000, "WS_DISABLED", 0x08000000, "WS_CLIPSIBLINGS", 0x04000000, "WS_CLIPCHILDREN", 0x02000000, "WS_MAXIMIZE", 0x01000000, "WS_CAPTION", 0x00C00000, "WS_BORDER", 0x00800000, "WS_DLGFRAME", 0x00400000, "WS_VSCROLL", 0x00200000, "WS_HSCROLL", 0x00100000, "WS_SYSMENU", 0x00080000, "WS_THICKFRAME", 0x00040000, "WS_GROUP", 0x00020000, "WS_TABSTOP", 0x00010000, "WS_MINIMIZEBOX", 0x00020000, "WS_MAXIMIZEBOX", 0x00010000, "WS_TILED", 0x00000000, "WS_ICONIC", 0x20000000, "WS_SIZEBOX", 0x00040000, "WS_OVERLAPPEDWINDOW", 0x00CF0000, "WS_POPUPWINDOW", 0x80880000, "WS_CHILDWINDOW", 0x40000000, "WS_TILEDWINDOW", 0x00CF0000, "WS_ACTIVECAPTION", 0x00000001, "WS_GT", 0x00030000), ExStyles := Map("WS_EX_DLGMODALFRAME", 0x00000001, "WS_EX_NOPARENTNOTIFY", 0x00000004, "WS_EX_TOPMOST", 0x00000008, "WS_EX_ACCEPTFILES", 0x00000010, "WS_EX_TRANSPARENT", 0x00000020, "WS_EX_MDICHILD", 0x00000040, "WS_EX_TOOLWINDOW", 0x00000080, "WS_EX_WINDOWEDGE", 0x00000100, "WS_EX_CLIENTEDGE", 0x00000200, "WS_EX_CONTEXTHELP", 0x00000400, "WS_EX_RIGHT", 0x00001000, "WS_EX_LEFT", 0x00000000, "WS_EX_RTLREADING", 0x00002000, "WS_EX_LTRREADING", 0x00000000, "WS_EX_LEFTSCROLLBAR", 0x00004000, "WS_EX_CONTROLPARENT", 0x00010000, "WS_EX_STATICEDGE", 0x00020000, "WS_EX_APPWINDOW", 0x00040000, "WS_EX_OVERLAPPEDWINDOW", 0x00000300, "WS_EX_PALETTEWINDOW", 0x00000188, "WS_EX_LAYERED", 0x00080000, "WS_EX_NOINHERITLAYOUT", 0x00100000, "WS_EX_NOREDIRECTIONBITMAP", 0x00200000, "WS_EX_LAYOUTRTL", 0x00400000, "WS_EX_COMPOSITED", 0x02000000, "WS_EX_NOACTIVATE", 0x08000000)out .= 'Style: 'try {out .= (style := WinGetStyle(hWnd)) " ("for k, v in Styles {if v && style & v {out .= k " | "style &= ~v}}out := RTrim(out, " |")if styleout .= (SubStr(out, -1, 1) = "(" ? "" : ", ") "Unknown enum: " styleout .= ")" Separator} catchout .= "#ERROR" Separatorout .= 'ExStyle: 'try {out .= (style := WinGetExStyle(hWnd)) " ("for k, v in ExStyles {if v && style & v {out .= k " | "style &= ~v}}out := RTrim(out, " |")if styleout .= (SubStr(out, -1, 1) = "(" ? "" : ", ") "Unknown enum: " styleout .= ")" Separator} catchout .= "#ERROR" Separatorif Verbose {out .= 'TransColor: 'try out .= WinGetTransColor(hWnd) Separatorcatchout .= "#ERROR" Separatorout .= 'Transparent: 'try out .= WinGetTransparent(hWnd) Separatorcatchout .= "#ERROR" SeparatorPrevDHW := DetectHiddenText(0)out .= 'Text (DetectHiddenText Off): 'try out .= '"' WinGetText(hWnd) '"' Separatorcatchout .= "#ERROR" SeparatorDetectHiddenText(1)out .= 'Text (DetectHiddenText On): 'try out .= '"' WinGetText(hWnd) '"' Separatorcatchout .= "#ERROR" SeparatorDetectHiddenText(PrevDHW)out .= 'StatusBar Text: 'try out .= '"' StatusBarGetText(1, hWnd) '"' Separatorcatchout .= "#ERROR" Separator}if Verbose > 1 {out .= 'Controls (ClassNN): ' Separatortry {for ctrl in WinGetControls(hWnd)out .= '`t' ctrl Separator} catchout .= "#ERROR" Separator}return SubStr(out, 1, -StrLen(Separator))
}