AutoHotkey 中的脚本同时按下 Windows 按钮和向左箭头

Script in AutoHotkey to Press Windows button and Left Arrow simultaneously

我想在 autohotkey 中编写一个脚本,这样每次我在 PC 上打开我的字典应用程序时,键 Windows+LeftArrow[=同时按下 30=] 结果,它会捕捉显示器左侧的 windows。

我试过这个:

#IfWinActive Oxford Advanced Learner's Dictionary
Send, #{Left}
return

还有这个:

#IfWinActive Oxford Advanced Learner's Dictionary
Send, {LWinDown}{Left}{LWinup}
return

但是当我打开应用程序时,他们中的任何一个都没有注意到。

编辑:

正如@Charlie Armstrong 所建议的那样,真正的问题是:如何在每次启动某个程序时制作代码块运行? 所以#IfWinActive 可能没有用。

一种方法是定期检查是否创建了新的 process/window 并检查它是否是我们要与之交互的 process/window。

第一个示例基于进程已 created/destroyed 时的 COM 通知。

; help for question: 
; 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, 0, 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.

相匹配的新 windows
; help for question: 
; by joedf (16:17 2021/02/28)

#Persistent

MyWatchedWindowTitle := "Oxford Advanced Learner's Dictionary"
SetTitleMatchMode, 2 ;this might not be needed, 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, 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
}

我认为您最大的问题是 AHK 似乎不能很好地捕捉 windows(根据我的快速研究和测试)。不过,效果好的是 WinMove.

我假设您是从快捷方式图标启动程序,但我建议使用启动程序的键盘快捷方式,然后从脚本定位 window。下面是一些示例代码,它打开 Notepad2.exe,等待 200 毫秒,然后移动 window 并调整它的大小:

^+!n:: ; Control+Shift+Alt+N to Open Notepad
Run C:\Program Files\Notepad2\Notepad2.exe
sleep, 200
WinMove, Notepad2,, 10, 20, 800, 600
return