如何用AHK判断一个Window在屏幕上是否可见?

问题描述 投票:0回答:3

我尝试从这里运行此脚本https://autohotkey.com/board/topic/25619-detect-on-screen/,但如果窗口顶部边框未接触屏幕顶部,则该脚本不起作用:

^F2::
If ( ID := WinExist("Calculator") ) 
 {
   WinGetPos , X, Y, , , ahk_id %ID%
   If  ( DllCall("WindowFromPoint", Int,X+5, Int,Y+5 ) = ID ) 
       MsgBox, Calculator is ON SCREEN
 }
Return
windows autohotkey
3个回答
0
投票

使用

    det_winIsVisible := WinGetStyle("ahk_id " . hwnd) & WS_VISIBLE

WS_VISIBLE                := 0x10000000

; Is a Window Visible on Screen - AutoHotkey Community
; https://www.autohotkey.com/boards/viewtopic.php?t=107797
;
; WinGetStyle / WinGetExStyle - Syntax & Usage | AutoHotkey v2
; https://www.autohotkey.com/docs/v2/lib/WinGetStyle.htm
/**
 * 
 * @param hwnd - The window handle.
 * @returns {Boolean|""} - true if visible, false if hidden, null if non-existent.
 */
detm_winIsVisible(hwnd) {
  DetectHiddenWindows_prev := DetectHiddenWindows(true)
  try {
    det_winIsVisible := WinGetStyle("ahk_id " . hwnd) & WS_VISIBLE
    return det_winIsVisible
  } catch TargetError as e {
    return ""
  } finally {
    DetectHiddenWindows(DetectHiddenWindows_prev)
  }
}
  • ahk v2
  • 不是最好的,也许 Dll 可以更好

-1
投票

作为检查窗口是否可见的替代方法,您可以随时间比较窗口文本内容并确定它是否足够您使用。

在此示例中,我正在检查

Media Player Home Cinema
窗口播放时间,以确定是否应该按
Media Play/Stop
按钮,或者聚焦于
Media Player Home Cinema
窗口并按
Space
(直接播放/停止):

Pause::
window_identifier = ahk_class MediaPlayerClassicW
WinGetTitle, window_title, %window_identifier%

if( !window_title ) {
    Send {Media_Play_Pause}
}
else {
    WinWaitActive, %window_title%, , 0.1
    is_window_focused := true
    if( ErrorLevel ) {
        ; MsgBox, WinWait timed out.
        is_window_focused := false
    }
    else {
        PlayPauseVideo()
        return
    }

    counter := 5
    first_result := GetRunningWindowText(window_title)

    while( counter > 0) {
        sleep, 200
        counter := counter - 1
        second_result := GetRunningWindowText(window_title)

        if( first_result != second_result ) {
            PlayPauseVideo()
            return
        }
    }

    if( is_window_focused ) {
        PlayPauseVideo()
    }
    else {
        Send {Media_Play_Pause}
    }
}
GetRunningWindowText(window_title) {
    WinGetText, window_text, %window_title%

    ; FoundPos := RegExMatch(window_text, "O)(?:\d\d:)+(?<frames>\d\d)", first_result)
    FoundPos := RegExMatch(window_text, "O)drawn: (?<frames>\d+)", first_result)

    ; Msgbox % first_result.Count() ": " first_result.Name(1) "=" first_result["frames"]
    return first_result["frames"]
}

PlayPauseVideo() {
    ; Msgbox, It is running video...
    WinActivate, ahk_class MediaPlayerClassicW
    Send {Space}
}
return

参考资料:

  1. https://autohotkey.com/docs/commands/RegExMatch.htm
  2. 如何在自动热键中创建 while 循环,当我按 {Ctrl} 时会中断?
  3. https://autohotkey.com/board/topic/35905-how-to-get-ahk-to-wait-a-specified-amount-of-time/
  4. http://rouge.jneen.net/

额外

重写函数中的主要代码以实现更好的泛化/重用:

Pause::CheckForPlayerWindow("ahk_class MediaPlayerClassicW",
        "{Media_Play_Pause}", "{Space}", "false")

^!Left::CheckForPlayerWindow("ahk_class MediaPlayerClassicW", "{Media_Prev}", "^p")
^!Right::CheckForPlayerWindow("ahk_class MediaPlayerClassicW", "{Media_Next}", "^n")


; https://stackoverflow.com/questions/55670223/how-to-determine-whether-a-window
CheckForPlayerWindow(window_identifier, media_key, player_key, reactive=true) {
    WinGetTitle, window_title, %window_identifier%

    if( !window_title ) {
        Send % media_key
    }
    else {
        WinWaitActive, %window_title%, , 0.1
        is_window_focused := true

        if( ErrorLevel ) {
            ; MsgBox, WinWait timed out.
            is_window_focused := false
        }
        else {
            PlayPauseVideo(window_identifier, player_key, reactive)
            return
        }

        counter := 5
        first_result := GetRunningWindowText(window_title)

        while( counter > 0) {
            sleep, 200
            counter := counter - 1
            second_result := GetRunningWindowText(window_title)

            if( first_result != second_result ) {
                PlayPauseVideo(window_identifier, player_key, reactive)
                return
            }
        }

        if( is_window_focused ) {
            PlayPauseVideo(window_identifier, player_key, reactive)
        }
        else {
            Send % media_key
        }
    }
}
GetRunningWindowText(window_title) {
    WinGetText, window_text, %window_title%

    ; FoundPos := RegExMatch(window_text, "O)(?:\d\d:)+(?<frames>\d\d)", first_result)
    FoundPos := RegExMatch(window_text, "O)drawn: (?<frames>\d+)", first_result)

    ; Msgbox % first_result.Count() ": " first_result.Name(1) "=" first_result["frames"]
    return first_result["frames"]
}

PlayPauseVideo(window_identifier, player_key, reactive=true) {
    ; Msgbox, It is running video...

    if( reactive == true ) {
        WinGetActiveTitle, active_window_title
    }

    WinActivate, %window_identifier%
    SendInput % player_key

    if( reactive == true ) {
        WinActivate, %active_window_title%
    }
}
return

新参考:

  1. https://autohotkey.com/docs/commands/Send.htm
  2. https://autohotkey.com/board/topic/77928-ctrl-v-sendinput-v-is-not-working-in-many-applications/
  3. https://autohotkey.com/board/topic/148483-how-to-pass-a-key-in-a-function-parameter/
  4. https://autohotkey.com/docs/KeyList.htm

-1
投票

它不起作用,因为 Windows API

https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-windowfrompoint
的函数 WindowFromPoint 被错误使用。

它只需要 1 个参数,而不是传递的 2 个参数。如果您需要,此函数可以正确地将 2 个参数转换为 1 个参数:

WindowFromPoint(x, y)
{
    VarSetCapacity(POINT, 8)
    Numput(x, POINT, 0, "int")
    Numput(y, POINT, 4, "int")
    return DllCall("WindowFromPoint", int64, NumGet(POINT, 0, "int64"))
}

完整示例:

Pause::
window_identifier = ahk_class MediaPlayerClassicW

WinGetTitle, window_title, %window_identifier%
is_visible := IsWindowVisible(window_identifier)

If( is_visible > 0 ) {
    MsgBox, Window %window_title% is visible!
}
else {
    If( is_visible < 0 ) {
        MsgBox, Window %window_identifier% not found!
    } else
    {
        MsgBox, Window %window_title% is NOT visible!
    }
}
IsWindowVisible(window_name) {
    ID := WinExist(window_name)

    If( ErrorLevel != 0 ) {
        ; MsgBox, Window %window_name% not found!
        return -1
    }

    If( ID > 0 ) {
        WinGetPos, X, Y, , , ahk_id %ID%
        active_window_id_hwnd := WindowFromPoint(X, Y)

        ; MsgBox, %X%, %Y%, %active_window_id_hwnd%
        If( active_window_id_hwnd = ID ) {
            ; MsgBox, Window %window_name% is visible!
            return 1
        }
        else {
            ; MsgBox, Window %window_name% is NOT visible!
            return 0
        }
    }

    ; MsgBox, Window %window_name% not found!
    return -1
}

WindowFromPoint(x, y)
{
    VarSetCapacity(POINT, 8)
    Numput(x, POINT, 0, "int")
    Numput(y, POINT, 4, "int")
    return DllCall("WindowFromPoint", int64, NumGet(POINT, 0, "int64"))
}
Return

参考资料:

  1. https://autohotkey.com/board/topic/116760-windowfrompoint-broken-in-windows-81/
  2. https://autohotkey.com/board/topic/11978-inidelete-set-errorlevel-if-section-or-key-doesnt-exist/
© www.soinside.com 2019 - 2024. All rights reserved.