问题描述
我想在 autohotkey 中编写一个脚本,以便每次我在 PC 上打开我的字典应用程序时,同时按下 Windows+LeftArrow 键并作为结果,它会捕捉显示器左侧的窗口。
我试过了:
#IfWinActive Oxford Advanced Learner's Dictionary
Send,#{Left}
return
还有这个:
#IfWinActive Oxford Advanced Learner's Dictionary
Send,{LWinDown}{Left}{LWinup}
return
但是当我打开应用程序时,他们中的任何一个都注意到了。
编辑:
正如@Charlie Armstrong 所建议的,真正的问题是:如何在每次启动某个程序时运行一段代码?所以 #IfWinActive
可能对以下情况没有用。
解决方法
一种方法是定期检查是否创建了新进程/窗口,并检查它是否是我们想要与之交互的进程/窗口。
第一个示例基于创建/销毁进程时的 COM 通知。
; help for question: https://stackoverflow.com/q/66394326/883015
; by joedf (16:04 2021/02/28)
MyWatchedWindowTitle := "Oxford Advanced Learner's Dictionary"
NewProcess_CheckInterval := 1 ; in seconds
SetTitleMatchMode,2 ;this might not be needed,makes the check for "contains" instead of "same" winTitle
hWnds := []
gosub,initialize_NewProcessNotification
return
; Called when a new process is detected
On_NewProcess(proc) {
global hWnds
global MyWatchedWindowTitle
; get the window handle,if possible
if (hwnd:=WinExist("ahk_pid " proc.ProcessID)) {
WinGetTitle,wTitle,ahk_id %hwnd%
; check if there is a visible window
if (wTitle)
{
; if so,check if it's a window we want to interact with
if (InStr(wTitle,MyWatchedWindowTitle))
{
; check if we've interacted with this specific window before
if (!ArrayContains(hWnds,hwnd)) {
; we havent,so we do something with it
hWnds.push(hwnd) ; keep in memory that we have interacted with this window ID before.
DoSomething(hwnd) ; the keys we want to send to it
}
}
}
}
}
DoSomething(hwnd) {
; size and move window to the left
SysGet,MonitorWorkArea,MonitorWorkArea
posY := 0
posX := 0
width := A_ScreenWidth // 2
height := MonitorWorkAreaBottom
WinMove,ahk_id %hwnd%,%posX%,%posY%,%width%,%height%
; multi-montitor support,more examples,and more complete snapping functions can be found here:
; https://gist.github.com/AWMooreCO/1ef708055a11862ca9dc
}
ArrayContains(haystack,needle) {
for k,v in haystack
{
if (v == needle)
return true
}
return false
}
initialize_NewProcessNotification:
;////////////////////////////// New Process notificaton ////////////////////////
; from Lexikos' example
; https://autohotkey.com/board/topic/56984-new-process-notifier/#entry358038
; Get WMI service object.
winmgmts := ComObjGet("winmgmts:")
; Create sink objects for receiving event noficiations.
ComObjConnect(createSink := ComObjCreate("WbemScripting.SWbemSink"),"ProcessCreate_")
ComObjConnect(deleteSink := ComObjCreate("WbemScripting.SWbemSink"),"ProcessDelete_")
; Set event polling interval,in seconds.
interval := NewProcess_CheckInterval
; Register for process creation notifications:
winmgmts.ExecNotificationQueryAsync(createSink,"Select * from __InstanceCreationEvent"
. " within " interval
. " where TargetInstance isa 'Win32_Process'")
; Register for process deletion notifications:
winmgmts.ExecNotificationQueryAsync(deleteSink,"Select * from __InstanceDeletionEvent"
. " within " interval
. " where TargetInstance isa 'Win32_Process'")
; Don't exit automatically.
#Persistent
return
; Called when a new process is detected:
ProcessCreate_OnObjectReady(obj) {
proc := obj.TargetInstance
/*
TrayTip New Process Detected,% "
(LTrim
ID:`t" proc.ProcessID "
Parent:`t" proc.ParentProcessID "
Name:`t" proc.Name "
Path:`t" proc.ExecutablePath "
Command line (requires XP or later):
" proc.CommandLine
)
*/
On_NewProcess(proc)
}
; Called when a process terminates:
ProcessDelete_OnObjectReady(prm) {
/*
obj := COM_DispGetParam(prm,9)
proc := COM_Invoke(obj,"TargetInstance")
COM_Release(obj)
TrayTip Process Terminated,% "
(LTrim
ID:`t" COM_Invoke(proc,"Handle") "
Name:`t" COM_Invoke(proc,"Name")
)
COM_Release(proc)
*/
}
第二个示例可能更简单一些,它会定期检查与搜索到的 WinTitle
匹配的新窗口。
; help for question: https://stackoverflow.com/q/66394326/883015
; by joedf (16:17 2021/02/28)
#Persistent
MyWatchedWindowTitle := "Oxford Advanced Learner's Dictionary"
SetTitleMatchMode,makes the check for "contains" instead of "same" winTitle
SetTimer,checkForNewWindow,1000 ;ms
hWnds := []
return
checkForNewWindow() {
global hWnds
global MyWatchedWindowTitle
; first check if there is at least one window that matches our winTitle
if (hwnd:=WinExist(MyWatchedWindowTitle)) {
; get all window matches
WinGet,wArray,List,%MyWatchedWindowTitle%
; loop through all windows that matched
loop % wArray
{
hWnd := wArray%A_Index%
; check if we've interacted with this specific window before
if (!ArrayContains(hWnds,hwnd)) {
; we havent,so we do something with it
hWnds.push(hwnd) ; keep in memory that we have interacted with this window ID before.
DoSomething(hwnd) ; the keys we want to send to it
}
}
}
}
DoSomething(hwnd) {
; size and move window to the left
SysGet,v in haystack
{
if (v == needle)
return true
}
return false
}
,
我认为您最大的问题是 AHK 似乎不适用于捕捉窗口(根据我的快速研究和测试)。不过,有效的是 WinMove。
我假设您是从快捷方式图标启动程序,但我建议使用键盘快捷方式启动程序,然后从脚本定位窗口。下面是一些示例代码,它打开 Notepad2.exe,等待 200 毫秒,然后移动窗口并调整其大小:
^+!n:: ; Control+Shift+Alt+N to Open Notepad
Run C:\Program Files\Notepad2\Notepad2.exe
sleep,200
WinMove,Notepad2,10,20,800,600
return