First clic = do something, (later) 2nd clic do something else

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Ahk-parrenti

First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 07:07

Hello,

I'm in trouble. I want to create a script :
When i right click (one time) for the first time : the letter "n" is press and release, and the letter "b" is press and stay press.
Later, when i will right click (one time) for a second time, the letter "b" is released.

I tryed so many way, nothing works. (for testing i replace "b release" by "po", i can see if its working on note pad like that)


Looping methode via variable value :
Etatbutton := "1stclic"

Departboucle:

RButton::
if Etatbutton := "1stclic"
{
send, n{b down}
Etatbutton := "2ndclic"
Goto, Departboucle
}

if Etatbutton := "2ndclic"
{
send, x{b up}
Etatbutton := "1stclic"
Goto, Departboucle
}

A Listen in a Listen :
RButton::
{
send, nb
KeyWait, RButton, po
}


Control script via label version :
"
1listen:
KeyWait, RButton, nb
Goto, 2listen

2listen:
KeyWait, RButton, po
Goto, 1listen
"

Big fail ! Someone can help me ? :)
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 08:11

Code: Select all

RButton::Send, % (shouldSendAlternate := !shouldSendAlternate) ? "n{b Down}" : "{b Up}"
dont code in your native language please, unless english of course
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 08:15

Code: Select all

Etatbutton := "1stclic"

Departboucle:

RButton::
	if Etatbutton := "1stclic" 
	{
		send, n{b down}
		Etatbutton := "2ndclic"
		Goto, Departboucle
	}
	
	if Etatbutton := "2ndclic"
	{
		send, x{b up}
		Etatbutton := "1stclic"
		Goto, Departboucle
	}
There are three problems with this piece of code. The first is that (in most cases) you never want to use the assignment operator := in an if statement. You need to use an equivalency operator instead, = or == (second one is case-sensitive).

The second problem is that once the first If statement resolves, Etatbutton is set to 2ndclic. That means that when it hits the second if statement, THAT statement reads as true and the second block activates immediately.

The third problem is the Goto statement, which because of issue #2 theoretically turns this into an infinite loop and I'm surprised you haven't had this just constantly spam nbxnbxnbxnbxnbxnbx etc as soon as you right click.

Try this:

Code: Select all

Etatbutton := "1stclic"

Rbutton::
if (Etatbutton = "1stclic" )
{
	send, n{b down}
	Etatbutton := "2ndclic"
}
else
{
	send, x{b up}
	Etatbutton := "1stclic"
}
return
Ahk-parrenti

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 08:50

swagfag wrote:

Code: Select all

RButton::Send, % (shouldSendAlternate := !shouldSendAlternate) ? "n{b Down}" : "{b Up}"
dont code in your native language please, unless english of course
Sorry. I thought the variable names were not important to you. Because I could very well call them simply "x" (so no info). But next time I'll be careful.

In any case, thank you very much for your answer and your code that works perfectly! I will look at its structure more carefully. And thank you again for your reactivity. :bravo: :D
Ahk-parrenti

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 09:16

MaxAstro wrote:

Code: Select all

Etatbutton := "1stclic"

Departboucle:

RButton::
	if Etatbutton := "1stclic" 
	{
		send, n{b down}
		Etatbutton := "2ndclic"
		Goto, Departboucle
	}
	
	if Etatbutton := "2ndclic"
	{
		send, x{b up}
		Etatbutton := "1stclic"
		Goto, Departboucle
	}
There are three problems with this piece of code. The first is that (in most cases) you never want to use the assignment operator := in an if statement. You need to use an equivalency operator instead, = or == (second one is case-sensitive).

The second problem is that once the first If statement resolves, Etatbutton is set to 2ndclic. That means that when it hits the second if statement, THAT statement reads as true and the second block activates immediately.

The third problem is the Goto statement, which because of issue #2 theoretically turns this into an infinite loop and I'm surprised you haven't had this just constantly spam nbxnbxnbxnbxnbxnbx etc as soon as you right click.

Try this:

Code: Select all

Etatbutton := "1stclic"

Rbutton::
if (Etatbutton = "1stclic" )
{
	send, n{b down}
	Etatbutton := "2ndclic"
}
else
{
	send, x{b up}
	Etatbutton := "1stclic"
}
return

For the first problem, I read and understood that:
: = it was for class type (STR) in Python, (string, text)
== it was for class type (INT) in Python. (integer, number)

As I wanted text and not numbers I put: =. I did not understand anything. But good to know.

For the second problem, this is what I do not understand: Once the first If statement resolves, Etatbutton is set to 2ndclic AND it should not read the second since I return it to "startboucle" and as the rbutton is not presumed pressed at this time, nothing should be played (neither the first statement nor the 2nd statement).

Later when I press the rbutton, then the first if statement is read, but not played because etatbutton is "2nd click", and the second if statement is read AND PLAY because etatbutton is 2nd click. at the end of this statement Etatbutton is set to 2ndclic.

For the third point, you do not have to be surprised since it happens exactly what you predict lol And that I do not understand the logic! The Rbutton is not continually pressed THEN once returned to Departboucle(Start loop in english) so nothing should happen until I press Rbutton. Then as etatbutton alternately changes value, the reaction of the Rbutton should change alternately as well.

Do you understand the logic I tried to write with this code? Why does not it stop? What's wrong ?

In any case, a BIG thank you for your code that works very well and ESPECIALLY for your explanation that makes me progress! Thank you for taking the time to explain to me what's wrong! :thumbup: :D
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 10:45

Hotkeys are labels, not if statements. They mark a point in code, they do not halt execution when reached. Only a return statement will do that. As an example, try this code:

Code: Select all

^z::
MsgBox First message!

^x::
MsgBox Second message!
return

^c::
MsgBox Third Message!
return
You will notice that pressing Ctrl + X will only display "Second Message", and pressing Ctrl + C will only display "Third Message". But pressing Ctrl + Z will display "First Message" and then "Second Message" because there is no return statement.
Ahk-parrenti

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 12:28

ok, that's it. I think I understood. I thought that the "goto" would do the work of the "return" (which I did not know existed). But apparently the goto does not work in this case... If I replace with return : it works better.

Big syntax problem too! The forgetfulness of parenthesis after the "if",was a big problem. Finally, the: = and = as you explained it to me!

And yes, I should have to use the "Else". How I did not think about it instead of giving an "if" condition.

Big thanks to you MaxAstro, you learn me a lot !


swagfag, your code is too complicated to read for me (for now) the "%" and the "?" disturb me! I am going to dig! Because the optimization level ... you wrote in one line what I created for several lines lol we see the degree of expertise ... lol

I let the thread open. If you want to complete your lesson to me MaxAstro or if you want to explain to me your code swagfag... Anyway. Thank you so much. You guyz are awesome. It's my first contact with the autohotkey's community and you represent it well. I love this language and I love you ;)
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 14:24

Code: Select all

RButton::
{
	; uninitialized variable starts off blank, then we assign its logical negation to it.
	; blank "" is considered as false, so the negation becomes true.
	; the next time RButton is triggered, its state will be flipped, becoming false
	; and so on and so on
	shouldSendAlternate := !shouldSendAlternate ; the variable is now set to true

	if (shouldSendAlternate) {
		Send, n ; press and release
		Send, {b Down} ; press
	}
	else {
		Send, {b Up} ; release
	} 
return
}
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: First clic = do something, (later) 2nd clic do something else

18 Apr 2018, 15:35

What swagfag used is called a ?: statement or a "ternary operator". It is basically a shorthand way of writing a simple if else statement. It is formatted like this:
( conditional expression ? code to execute if true : code to execute if false)

For an example, try the following script:

Code: Select all

X := 5

Msgbox % ( X < 10 ? "X is less than ten." : "X is ten or greater.")
return
You will see that changing the value of X changes the messagebox that pops up.

The second thing swagfag used is the fairly advanced trick (which you actually accidentally included in your original code) of putting an assignment expression into an if statement. When you do that, the assignment is completed and THEN the if is evaluated. For example, in the following code:

Code: Select all

MyVar := false
if (MyVar := true)
	MsgBox Hello!
You will notice that the messagebox DOES pop up, even though MyVar is initially set to false. This is because MyVar := true sets the variable to true, and THEN the if statement is checked. This is very useful for making toggles, because putting an ! in front of a variable resolves to the opposite of that variable. So if MyVar is true, then !MyVar is false. So look at this example:

Code: Select all

MyVar := false

Rbutton::
if (MyVar := !MyVar)
	MsgBox Hello
else
	MsgBox World
Each time you right click, the if statement is evaluated, and MyVar := !MyVar causes MyVar to set to true if it was false, and false if it was true. The result of that is then used to evaluate the if statement. So the first time you right click, the messagebox says "Hello", the second time it says "World", and it alternates between the two.

Putting it all together, then, this line:

Code: Select all

RButton::Send, % (shouldSendAlternate := !shouldSendAlternate) ? "n{b Down}" : "{b Up}"
Reads "When you click the right mouse button, invert the value of shouldSendAlternate. Then, if shouldSendAlternate is true, send "n{b down}. Otherwise, send "{b up}".
Ahk-parrenti

Re: First clic = do something, (later) 2nd clic do something else

19 Apr 2018, 09:49

Thank you very much, I learned lots of new things from you both.
MaxAstro thank you for these detailed explanations, you are REALLY a big help.
I close the subject, I think we have seen everything. Once again thank you. ;)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 215 guests