Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Hotkey doesn't work on first press, only second.



  • Please log in to reply
6 replies to this topic
SputnikDX
  • Members
  • 9 posts
  • Last active: Nov 05 2015 02:48 PM
  • Joined: 15 Oct 2015

The intent is for the hotkey to toggle between MsgBox's popping up notating each decision the script makes in a QA process. The hotkey does what I expect it to do, but ONLY after I press it twice. The hotkey is off by default, is off when I press it, and on when I press it the second time.

 

Here's the toggle script:

toggleMessageBox := false
^F1::MsgBox %help%
^F2::pause ;	F2 pauses and unpauses the script
^F3::
if toggleMessageBox = false
{
   toggleMessageBox = true
   return
}	
else
{
   toggleMessageBox = false
   return	
}

Where the toggle takes effect works fine, but I'll post it anyway for clarity:

if toggleMessageBox = true
{
   MsgBox,,,Issue date not found. The VIN has no match.,10000
}

There's a few instances of that script, with different MsgBox's. On a side, the timeout's don't work but it's not important to me right now.

 

Lastly, here's the log of the script as it starts, and the three hotkey presses:

042: toggleMessageBox := false
043: Return (7.33)
046: if toggleMessageBox = false
053: toggleMessageBox = false
054: Return (1.90)
046: if toggleMessageBox = false
048: toggleMessageBox = true
049: Return (2.71)
046: if toggleMessageBox = false
053: toggleMessageBox = false
054: Return (0.91)


Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012

Which hotkey needs to be pressed twice? I'm guessing the ^F3::.  Are you sure this line is in the auto-execute section? Your log suggests it may not be because you're looking at lines 40+: toggleMessageBox := false.

 

But of note, := and = are very different. I recommend you stick with = in this case - toggleMessageBox = false. But you could also do toggleMessageBox := "false", I think. My mind isn't quite able to explain the differences between expressions and literal strings when it comes to ifs.



Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I recommend you stick with = in this case - toggleMessageBox = false

I'm going to recommend the opposite.

Don't use the words "true" and "false". Use binary 0 or 1. The built-in true returns 1 and false returns 0.
if (toggleMessageBox = false)  ; Use parentheses.
{
   toggleMessageBox := true  ; Use :=
   return
}	
else
{
   toggleMessageBox := false  ; Use :=
   return	
}
Too verbose!
  • You can write if toggleMessageBox to mean "if toggleMessageBox is true", but you must not use toggleMessageBox = false or := "false" to set it. The word "false" is considered true, since it is neither zero (0) nor empty.
  • Since both branches return, you can remove both and instead return below the IF.
  • If only one line remains in each branch, you can omit the braces.
  • Since you're just toggling a boolean (true/false) value, there's a much shorter way:
^F3::toggleMessageBox := not toggleMessageBox
;or
^F3::toggleMessageBox := !toggleMessageBox
To use the toggle,
if toggleMessageBox
{
   MsgBox,,,Issue date not found. The VIN has no match.,10000
}
;or
if (toggleMessageBox = true)
{
   MsgBox,,,Issue date not found. The VIN has no match.,10000
}
; (braces are optional in this simple case)
If you repeat this pattern very often, you could use a function:
Problem("Issue date not found. The VIN has no match.")

Problem(message) {
    global
    if toggleMessageBox
        MsgBox,,, %message%, 10000
}
Technically if toggleMessageBox = %false% would be equivalent to if (toggleMessageBox = false), but I'd never use it. I rarely compare directly to true/false anyway.

When used as text, the words "true" and "false" have no special meaning. In that case, you may as well use more descriptive words, like toggleMessageBox = show.

SputnikDX
  • Members
  • 9 posts
  • Last active: Nov 05 2015 02:48 PM
  • Joined: 15 Oct 2015

If you repeat this pattern very often, you could use a function:
Problem("Issue date not found. The VIN has no match.")

Problem(message) {
    global
    if toggleMessageBox
        MsgBox,,, %message%, 10000
}
Technically if toggleMessageBox = %false% would be equivalent to if (toggleMessageBox = false), but I'd never use it. I rarely compare directly to true/false anyway.

 Well, Exaskryz fixed my issue by just changing it to = instead of :=. But I'm more interested in implementing functions. I have a different script with a ton of repeating actions, just with different variables. I can just define the action once as a function, and just pop that function down with each of the variables? Super cool. Thanks.



Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012
✓  Best Answer

Yeah, there were two ways to go about it, but I didn't justify what it was. I think I can explain it a bit better now (though Lexikos already has an explanation, I'll try going a bit more in-depth.)

 

true/false can be boolean (equivalent to non-zero and zero, often 1 and 0). But in your script, you're using them as strings - strings are have a boolean value of true. If you ever use if variable, the value false would make the if statement false, but the string false would make the if statement true. When I suggested to use the = operator, it stored the string inside your variable toggleMessageBox. This works fine when you use if toggleMessageBox = false - because that checks if the string on the right is inside the variable named on the left. However, if you use parentheses to encompass your if statement, it'll treat both side of the = as names of variables and retrieve their values.

 

Here's a quick example to demonstrate things:

1::
var = false
If var = false
   MsgBox, the string false is found inside the var
return
 
2::
var = false
if (var = false)
   MsgBox, this won't appear because it's really asking if var has no value
return

 

FYI, false is a reserved variable name, so you can't do something like false = string.

 

Some more examples. This is where we change to the := operator, which evaluates content on the right to the variable. As false has an inherent value of zero, which in all cases that I know of counts as "no value".

 

3::
var := false
If var = false
   MsgBox it won't appear because var does not contain the string false
return
 
4::
var := false
If (var = false)
   MsgBox var has no value, and the if statement is asking for that.
return

 

I should clarify for Lexikos that I meant in just this case for the simpler fix for the code. Indeed I agree it would probably be of better use to use := and boolean evaluations.



SputnikDX
  • Members
  • 9 posts
  • Last active: Nov 05 2015 02:48 PM
  • Joined: 15 Oct 2015

OK. I'll switch things around to make the Boolean. I thought they were in the first place, and didn't understand I was comparing strings when I'm not specifically treating them as expressions with :='s and ()'s. I chose "true false" for readability, so I should make it more understandable if I can.



Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I should clarify for Lexikos that I meant in just this case for the simpler fix for the code.

That was clear. My post wasn't about fixing this one script, but about recommending a better long term approach.

The "traditional" syntax (var = string, if var = string, etc.) is more limiting. If you do any more than trivial keyboard macros, eventually you will find a need to use expressions, so you may as well start early.