为什么表达式:If (A:=!A) 每次按下热键时的计算结果都不一样?

Why does the expression: If (A:=!A) evaluate differently each time a hotkey is pressed?

在 Autohotkey 脚本中,一旦用户按下 CapsLock 键,SplashText 应该弹出,表明它已打开,或者当它关闭时退出,这里的问题不在于让它工作的代码,而是它可以变得多么简单。

有不同的方法,有些需要大约 25 行,有些使用 SetTimerGetKeyState 内部函数和几个循环来达到 运行,有些只有五个,没有循环。

最简单的:

#SingleInstance Force
SetCapsLockState, Off


~CapsLock::
If (Tog:=!Tog)
SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
else
SplashTextOff

return

If (Tog:=!Tog) 怎么这么容易得到这个代码运行ning? Tog 只是一个未初始化的变量,每次按下 CapsLock 它都会不断地从 1 到 0

改变它的值

好像是在代码中充当Flag?我在这一行中缺少什么:

If (Tog:=!Tog)

是什么让它每次评估都不同?

下面是另一种方法 A = 0 作为开关工作,我做了这个,但它并没有我想要的那么简单是,但它完成了工作。

更长的代码:

#SingleInstance Force 
SetCapsLockState, Off

~CapsLock::

    If (A = 0) 
    {
    SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
    A=1
        }else
        {
        SplashTextOff
        A=0
        }

return 

最长的代码:

最后一个得到相同的结果,但检查密钥的实际物理状态它不会依赖脚本顶部的 SetCapsLockState, Off 来确保switch 将在一行中完成其余的工作,因为它更简单。

#SingleInstance Force
#Persistent

SetTimer, StateCapsLockON_Timer, 100
Return

~CapsLock::

StateCapsLockON_Timer
    If GetKeyState("CapsLock", "T")
    {
    SetTimer, StateCapsLockOFF_Timer, 100
    SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
    SetTimer, StateCapsLockON_Timer, Off
    }
 Return

StateCapsLockOFF_Timer:
    If !GetKeyState("CapsLock", "T")
    {
    SetTimer, StateCapsLockOFF_Timer, Off
    SplashTextOff
    SetTimer, StateCapsLockON_Timer, On
    }
Return

关于 If (Tog:=!Tog) 在这三个例子中最简单的例子中的工作方式有什么好的想法吗?

我现在知道了,检查 logical-not 这个 link:

https://lexikos.github.io/v2/docs/Variables.htm

如果操作数(在本例中为 Tog)为空或 0,则应用 logical-not(或 !Tog) 为 1,表示 "true"。否则,结果为 0(假)

if (Tog = 0)
  Tog = 1

会带来与以下相同的结果:

If Tog:=!Tog

因为在 If 甚至检查更改的值之前就已经发生了操作,所以 if 不仅仅是比较数据,操作发生在 if 之前,因为括号内的值不仅被读取而且还被更改并且变量被重新分配。

(表达式) 括号中的任何 sub-expression。例如,(3 + 2) * 2 强制首先计算 3 + 2。

主要区别在于赋值运算符 := 与比较运算符 = 的用法不同。因为,如您所见,您可以计算 if-statement 中的表达式,您实际上可以在同一个 if-statement 中包含两个运算符。这是一个例子:

f1::
If (( test := 3+2 ) = 5 )
    MsgBox
Return

这里"test"是先赋值3+2之和,然后和5进行比较。所以,关键是if-statements允许赋值,先赋值,也就是说,在比较任何内容并将其评估为真或假之前。

如果没有比较运算符(=、<、>、<=、>=),就像您的切换中的情况一样,它只会评估变量本身是真还是假。如果变量为空白、0 或 false,则计算结果为 false;其他一切都是真的,即使是字符串 "false".


现在有趣的是。如果我们使用 Progress 和 "zh0" 选项,我们实际上可以将您的代码减少到一行。

~CapsLock::Progress , % ( Tog := !Tog ) ? "zh0 w350 h35" : "Off" ,, [CapsLock] Activated. , Wanted !

不幸的是,SplashText 无法做到这一点,因为它们实际上是两个独立的命令。但好处是 Progress 实际上有更多可用选项,因此您可以更改字体大小和颜色等。