Autohotkey,切换布尔变量不能正常工作

Autohotkey, toggle boolean variable not work properly

我编写了一个 Autohotkey 程序来切换 Windows 内置放大镜的缩放级别。这很简单。当您将鼠标移动到左上角时,它会放大,下次您移动到左上角时它会缩小。下面是我的代码。问题是老是放大,不知道哪里出了问题。谁能帮忙看看?

; Timer to check mouse position
SetTimer, CheckMouse, 300

#Persistent
#SingleInstance force

WinGetPos,,,Xmax,Ymax,ahk_class Progman  ; get desktop size

T = 4   ; adjust tolerance value if desired

Xmax := Xmax - T   ; allow tolerance to mouse corner activation position
Ymax := Ymax - T

CheckMouse:                   ; check mouse position
CoordMode, Mouse, Screen
MouseGetPos, MouseX, MouseY

GetKeyState, SState, Shift
GetKeyState, AState, Alt
GetKeyState, CState, Control

zoom_toggle := True

if (MouseY < T and MouseX < T and CState = "U" and AState = "U" and SState = "U")
{
    if(zoom_toggle)
    {
        Send #{+}
        zoom_toggle := False
    }
    else
    {
        Send #{-}
        zoom_toggle := True
    }
}

Return

fix/improve.
的事情很少 我将从实际问题开始,然后再讨论您 should/could 改进的内容。

所以实际的问题是,每次你 运行 你的计时器,你都将 zoom_toggle 变量设置为 true。所以是的,每次重置值时尝试进行任何切换都没有多大帮助。
将定义移动到脚本的顶部,或者由于 ahk 的宽容程度,您实际上可以完全跳过声明变量。这样,当它首次使用时,它是使用默认值 nothing 创建的,计算结果为 false.

现在转到其他 fixes/improvements。
#directives 的位置。
Good/common 实践是在脚本的最顶部定义这些类型的#directives。

使用 WinGetPos 获取屏幕 width/height。
您可以使用 A_ScreenWidth and A_ScreenHeight 变量轻松获取屏幕宽度和高度。

缺少 return that should end your auto-execute section
当您第一次启动脚本时,没有什么可以阻止代码执行一直下降到计时器的回调标签。
在您的情况下,这不会造成任何不良结果,但为了将来参考,您不希望这种情况发生。使用 return 停止代码执行并结束自动执行部分。

冗余代码
无需每次 运行 定时器都设置 CoordMode。将此命令移动到脚本的顶部。
在您的发送命令中,无需将 - 包裹在 { } 中。这样做只是为了转义发送命令中具有特殊含义的字符,- 有 none。在特殊情况下,这样做甚至可能会遇到不需要的行为。 documentation.
中有更多相关信息 为什么要创建 XmaxYmax?他们什么都不为我们做?

Send instead of SendInput
的用法 SendInput 更快更可靠。应该几乎总是用于 Send.
您可以在脚本顶部指定 SendMode, Input 以将所有 Send 命令转换为 SendInput。我个人更喜欢只写 SendInput.

遗留代码
从技术上讲,使用遗留代码没有错,但绝对不推荐这样做。 与未来 AHK 版本的兼容性也不存在。表达式语法是现在应该始终使用的语法。
使用函数 GetKeyState() 而不是旧命令。
使用非旧版 operators&&|| 等)而不是旧版 ANDOR 等。 始终使用 := 而不是 =。从未使用过旧分配。
标签的使用也几乎是遗留的。应该替换为一个函数,但我应该确保你也理解函数范围。如果你愿意,我可以。

这是您修改后的代码:

#Persistent
#SingleInstance, Force
CoordMode, Mouse, Screen ;move this to the top, needs to be executed only once

; Timer to check mouse position
SetTimer, CheckMouse, 1000

T := 4   ; adjust tolerance value if desired
Xmax := A_ScreenWidth - T   ; allow tolerance to mouse corner activation position
Ymax := A_ScreenHeight - T
;not sure why we're creating these two variables though, they're doing absolutely nothing for us?

return ;end auto-execute section

CheckMouse:                   ; check mouse position
    MouseGetPos, MouseX, MouseY
    SState := GetKeyState("Shift", "P")
    AState := GetKeyState("Alt", "P")
    CState := GetKeyState("Control", "P") 
    ;returns true/false (1/0)
    ;true meaning the key is down

    if (MouseY < T && MouseX < T && !SState && !AState && !CState)
    {
        ;I skipped definin the zoom_toggle variable so it's created for us
        ;with the default value of nothing, which evaluates to false
        ;had to flip around the if statement to account for this as well
        if(!zoom_toggle) 
        {
            SendInput, #{+}
            zoom_toggle := true
        }
        else
        {
            SendInput, #-
            zoom_toggle := false
        }
    }
return ;ends the label

最后,我想说这不是一个很好的实现。为了使其至少可用,请将计时器更改为 运行 更慢。我在修改后的代码中做到了 1 秒。
如果你想让它变得更好,我可以提到一个超级简单的方法,就是当鼠标在该区域时只运行编码一次。为鼠标是否已退出该区域添加另一个开关即可。
此外,如果您在 Windows 中的主显示器左侧有第二台显示器,事情会变得很糟糕哈哈。