0
votes

In an Autohotkey script, once a user presses the CapsLock key, a SplashText should pop up indicating that it is ON, or out when it is OFF, the problem here is not about the code that gets it to work but how much simpler it can get.

There are different ways that do it, some need about 25 lines, some use SetTimer and GetKeyState internal functions and several loops to get it to run, some just about five and no loops.

Simplest:

#SingleInstance Force
SetCapsLockState, Off


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

return

How does: If (Tog:=!Tog) get this code running so easily? Tog is just a variable not initiated, and each time the CapsLock is pressed it is continuously changing its value from 1 to 0

It seems to be acting as a Flag in the code? what am I missing in this line:

If (Tog:=!Tog)

What makes it evaluate different each time?

This is one below is another approach with A = 0 working as a switch, I made this one and it doesn't quite get as simple as I'd like it to be but it does the job.

Longer code:

#SingleInstance Force 
SetCapsLockState, Off

~CapsLock::

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

return 

Longest code:

This last one gets the same result but checks the actual physical state of the key It wouldn't rely on SetCapsLockState, Off at the top of the script to make sure a switch will do the rest of the work in just one line as the simpler one.

#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

Any good ideas about the way If (Tog:=!Tog) works in the simplest of these three examples?

2
This is really not worthy of a full answer. The idea is very simple. You are doing assignment to a variable Tog := ... If you put an assignment inside of a logical evaluation (something) this will always evaluate to true, because the assignment will be made. When you assign to a variable the value Tog:=!Tog you can think of it as "Set Tog equal to the value of Not Tog. So if Tog was True, Not Tog is false. If Tog is False, Not Tog is true. This is a common toggling technique across programming languages.gview
@gview I had the impression that the if statement was just comparing values, had not gone as far as to notice that Tog was being reassigned, thank you for your feedback.Davith

2 Answers

1
votes

I got this now, check logical-not on this link:

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

If the operand (In this case Tog) is blank or 0, the result of applying logical-not (or !Tog) is 1, which means "true". Otherwise, the result is 0 (false)

if (Tog = 0)
  Tog = 1

would bring the same result as:

If Tog:=!Tog

Because an operation was taking place before the If even checked the changed value, if wasn't just comparing data, the operation was happening before the if since the values inside the parenthesis were not just being read but were also being changed and the variable being reassigned.

(expression) Any sub-expression enclosed in parentheses. For example, (3 + 2) * 2 forces 3 + 2 to be evaluated first.

0
votes

The key difference is the usage of the assignment operator := as opposed to the comparing operator =. Since, as you've seen, you can evaluate expressions in an if-statement, you can actually include both operators in the same if-statement. Here's an example:

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

Here "test" is first being assigned the sum of 3+2, then compared to 5. So, the key is that if-statements allow assignments to take place and that assignments take place first, that is, before anything is compared and evaluated to be true or false.

If there is no comparing operator (= , <, >, <=, >=), as is the case in your toggle, it just evaluates whether the variable itself is true or false. If the variable is blank, 0, or false, it evaluates to false; everything else is true, even the string "false".


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

Unfortunately, this isn't possible with SplashText since these are actually two separate commands. But the upside is that Progress actually has a lot more options available, so you can change the font size and color, etc.