Skip to content

Instantly share code, notes, and snippets.

@anonymous1184
Last active May 20, 2024 19:47
Show Gist options
  • Save anonymous1184/121870db8396046927e9090d45bf3037 to your computer and use it in GitHub Desktop.
Save anonymous1184/121870db8396046927e9090d45bf3037 to your computer and use it in GitHub Desktop.
Toggles

Toggles

Table of contents

What are they?

Toggles, as the name implies are a switch for a state. Is generally bound to turn on/off any given functionality. The most common usage is a binary 2-step toggle; non-binary and multiple-step toggles are less common but also seen.

Basic principle

You have a variable with a boolean value (1/0, true/false) and after you toggle it you change its value to the opposite state.

In Layman's terms: if the toggle is active, deactivate it; else vice versa.

test.ahk
toggle := false

if (toggle = true)
    toggle := false
else
    toggle := true

Considerations

  • One toggle per functionality. If you have multiple functionalities that need the usage of a toggle use a variable for each one, otherwise unintended effects might occur (like one functionality left running and the other not starting).

  • Always initialize the variable. While this is not forcefully necessary is the right way to do it. If using the #Warn directive an alert will be shown stating that the variable is not initialized, also might be needed to start the toggle in the "on" state.

    • This will show an alert:

      test.ahk
      #Warn
      
      if (toggle = true)
          toggle := false
      else
          toggle := true
    • This won't:

      test.ahk
      #Warn
      
      toggle := true
      
      if (toggle = true)
          toggle := false
      else
          toggle := true

Different implementations

We already checked the "lengthy" method that involves if/else combination, still, we have the:

  • Ternary Operator:

    test.ahk
    toggle := 0
    
    ; Integer values
    toggle := toggle = 1 ? 0 : 1
    MsgBox % toggle ; Shows 1
    
    ; Boolean values
    toggle := toggle = true ? false : true
    MsgBox % toggle ; Shows 0
  • Logical NOT*:

    test.ahk
    toggle := false
    
    toggle := !toggle
    MsgBox % toggle ; Shows 1
    
    toggle := !toggle
    MsgBox % toggle ; Shows 0

    * Applies to all languages, not just scripting like AutoHotkey or JavaScript.

  • Exclusive OR (XOR):

    test.ahk
    toggle := 0
    
    toggle ^= 1
    MsgBox % toggle ; Shows 1
    
    toggle ^= 1
    MsgBox % toggle ; Shows 0

Arbitrary pair

Sometimes values different than true and false are needed (eg yes/no, On/Off, 1/2, etc), those can be expressed with:

  • A ternary operator:

    test.ahk
    toggle = "Off"
    
    toggle := toggle = "On" ? "Off" : "On"
    MsgBox % toggle ; Shows "On"
    
    toggle := toggle = "On" ? "Off" : "On"
    MsgBox % toggle ; Shows "Off"
  • Or a tuple:

    test.ahk
    num := 2
    
    num := [2,1][num]
    MsgBox % num ; Shows 1
    
    num := [2,1][num]
    MsgBox % num ; Shows 2

Positive and Negative

Math is always a welcomed addition, makes it a breeze to swap values between a positive and its negative counterpart (eg, +1/-1):

test.ahk
num := 1

num *= -1
MsgBox % num ; Shows 1

num *= -1
MsgBox % num ; Shows -1

Bonus: display the + sign:

test.ahk
num := 1

num *= -1
MsgBox % Format("{:+d}", num) ; Shows -1

num *= -1
MsgBox % Format("{:+d}", num) ; Shows +1

Arbitrary number of values

When cycling through different values there are many possible options, the most common are:

  • Having an array of the values, looping through them, validating on each iteration if we are past the last member, if so, start over.

    test.ahk
    sizes := ["s", "m", "l", "xl"]
    sizesPosition := 0 ; Last position
    
    loop 8
        MsgBox % Cycle(sizes, sizesPosition)
    ; Shows: s, m, l, xl... s, m, l, xl...
    
    Cycle(obj, ByRef i) {
        if (obj.Count() = i)
            i := 1
        else
            i += 1
        return obj[i]
    }
    
    /* Compact form:
    Cycle(obj, ByRef i) {
        t := obj.Count()
        return obj[i += i = t ? 1 - t : 1]
    }
    */
  • Cycling through numbers starting in 0 or 1. Again, this relies on math (and the post-increment operator).

    test.ahk
    index0 := 0
    loop 6
        MsgBox % "index0: " CycleFrom0(index0, 3) "`n"
    ; Shows: 0,1,2... 0,1,2...
    
    index1 := 1
    loop 6
        MsgBox % "index1: " CycleFrom1(index1, 3) "`n"
    ; Shows: 1,2,3... 1,2,3...
    
    CycleFrom0(ByRef var, total) {
        return var++ := Mod(var, total)
    }
    
    CycleFrom1(ByRef var, total) {
        return var++ := Mod(var + total - 1, total) + 1
    }

Examples: toggles in hotkeys

Conditional directive

This example uses F1 to toggle the swapping of the mouse buttons. As recommended, initialize the toggle before the end of auto-execute.

test.ahk
toggle := 0

return ; End of auto-execute

F1::toggle ^= 1

#If toggle
    LButton::RButton
    RButton::LButton
#If

Conditional statement

The following example will place a ToolTip that follows the pointer announcing the current time. It uses a different method for each of the hotkeys.

F1 uses a timer to avoid being blocked by an infinite loop (like the one in F2).

For F2 to be able to stop and avoid being stuck in the infinite loop, the #MaxThreadsPerHotkey is needed. Just bear in mind that the directive is positional so it will affect every hotkey declared below.

test.ahk
toggle := 0

return ; End of auto-execute

F1::
    toggle ^= 1
    SetTimer TimeNow, % toggle ? 1 : "Delete"
    if (!toggle)
        ToolTip
return

#MaxThreadsPerHotkey 2
F2::
    toggle ^= 1
    while (toggle)
        TimeNow()
    ToolTip
return

TimeNow() {
    FormatTime now,, h:mm.ss tt
    ToolTip % "It's: " now
}

Hotkey command

Toggling the hotkey itself with native AHK functionality. In this case the Space will issue a message every time is pressed (you can toggle this with F1):

test.ahk
Space::MsgBox

F1::Hotkey Space, Toggle
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment