Issue returning proper mouse cords - autohotkey

In this problem setXTowerLocation() is called, a message box than appears after exiting the message box the function getXCords() is called in which it continuously scans checking the keyState of Lbutton once it detects that its pushed down the getxCords() function returns the x value of the cords of the mouse, which in turned gets set to a global variable in the setXTowerLocation() function before returning and displaying the x cord in a message box. Every time i run it the message box comes up blank, i have tested aspects of the code and they all seem to work individually so i believe it must be an error in syntax?
The ending message box is only for testing purposes. Thanks in advance :)
SendMode Input
Global xTowerLocation =
setXTowerLocation()
MsgBox, 0, MessageBox, %xTowerLocation%
getxCords()
{
xCord =
Loop,
{
GetKeyState, state, Lbutton
if(state = "D")
{
MouseGetPos, xx, yy
xCord := %xx%
return
}
}
return xCord
}
setXTowerLocation() {
MsgBox, 0, MessageBox, Begin?
IfMsgBox OK
xTowerLocation := getxCords()
return
}

Yes, syntax error in that xCord is referenced to a variable named after the contents (the mouse coord). Fix these two lines in getxCords() so xCord holds the value of the variable xx as follows:
xCord := xx
return xCord
And then no xCord on that later return (at end of the function).
EDIT: For even more fun, make the above xCord line as follows:
xCord := "x= " . xx . " , y= " . yy

Related

autohotkey use a return value imagesearch and click

I have a function:
NormalRand(x,y,int=1) {
Loop 12
{
Random, var,0.0,1
Num+=var
}
norm := (int) ? Round((y+x)/2+((Num-6)*(y-x))/6) : (y+x)/2+((Num-6)*(y-x))/6
Return norm < x ? x : norm > y ? y : norm
}
I have an imagesearch:
ImageSearch, FoundX, FoundY, 0, 0, A_ScreenWidth, A_ScreenWidth, *50 Okay.jpg
If ErrorLevel = 0
{
xCord = NormalRand(%FoundX%-10,%FoundX%+10)
yCord = NormalRand(%FoundY%-10,%FoundY%+10)
MsgBox, 4,, Found the image at %xCord% %yCord%
Click, %xCord%, %yCord% Left, 1
Sleep, 2000
}
I am trying to use the NormalRand function to distribute my clicks around the buttons so they are harder to detect within the program I will use this with. However, when i try to sent the cords to the click it doens't work. When i test it with msgbox i get this output Found the image at NormalRand(391-10,391+10) NormalRand(676-10,676+10)
I can't seem to figure out how to get it to send the numbers instead of the text.
What we have here, is misuse, and probably also unintentional use, of the legacy syntax.
Lets look at these two lines:
xCord = NormalRand(%FoundX%-10,%FoundX%+10)
yCord = NormalRand(%FoundY%-10,%FoundY%+10)
You're actually assigning text to those variables, not calling a function.
See this as an example:
xCord = NormalRand(%FoundX%-10,%FoundX%+10)
yCord = NormalRand(%FoundY%-10,%FoundY%+10)
MsgBox, % xCord "`n" yCord
For legacy syntax you're referencing the FoundX and FoundY variables correctly by wrapping them around %, but you're not doing that for the function name.
So in legacy syntax you'd do this:
xCord = %NormalRand%(%FoundX%-10,%FoundX%+10)
yCord = %NormalRand%(%FoundY%-10,%FoundY%+10)
However, please stop using legacy syntax. It's so ancient, bad and very different compared to other programming languages you maybe have experienced.
Expression syntax is what you want to use, so instead of legacy =, we're using := to assign an expression to our variables. (= is never ever used!)
In expression syntax your function calls look normal and nice:
xCord := NormalRand(FoundX-10, FoundX+10)
yCord := NormalRand(FoundY-10, FoundY+10)
And to preach even more about legacy syntax, you're also using it on the if-statement. To not use the legacy if-statement, use if ().

What happens when I try to copy an object with `thecopy := object` instead of object.Clone()?

thearray := [6,77,4,3,66,11]
thecopy := thearray
MsgBox % thecopy.Length() ; 6
thearray := function(thearray)
MsgBox % thecopy.Length() ; 0
MsgBox % thearray.Length() ; 6
Why is thecopy "ruined" when thearray is changed by a function? My guess: The function changes the thearray. Therefor thecopy, which I guess is some kind of reference (?) to the same array as 'thearray' was, is invalid or something. Is this the right way to think about this? I'm all new to this reference thing or whatever it is.
And by the way, if .Clone() is added in the end of the second row thecopy remains intact.

autohotkeys using ifwinactive with expression not working

I am using AutoHotKeys to test if a window is active along with an expression. I don't seem to be able to get it to work. I am assigning the expression to a variable and then testing for ifWinActive and the variable. AutoHotKeys doesn't seem to be able to evaluate the expression correctly. This is my script:
^W::
;hotkey always fires
done = false
SetTimer, CheckPopups, 10000 ; check every 10 seconds for window
CheckPopups:
this := (done != true)
#IfWinActive "Volume Spike - Down" and this
{
;specific lines only when active window is true and done is false
msgbox hello
done := true
}
IfWinNotActive Volume Spike - Down
{
done = false
}
When I launch the script and the window is not active, it shows the message box Hello. Then 10 seconds later it shows it again. It should only show the message box if the window is active and done = false. Any idea what I am doing wrong?
You're using #IfWinActive, which is a directive used to create conditional hotkeys. You should use IfWinActive instead.
You can also use the function version, WinActive() inside your if-clause. It makes it look a little cleaner in my opinion.
Here's a short example:
#Persistent
done := false
SetTimer, CheckPopups, 1000 ; Check every second for window
return
CheckPopups:
if ( WinActive("Volume Spike - Down") ) and (!done) {
msgBox, Hello
done := true
} else {
done := false
}
return

How do i parse a variable in a function to being able to define which variable to send?

This is my code
IniRead, custommessage1, whisperconfig.ini, messages, Message1
IniRead, custommessage2, whisperconfig.ini, messages, Message2
^NumPad1::whispermessage(1)
whispermessage(var){
finalwhisper := "custommessage" + var ;this equals custommessage1
Msgbox, %finalwhisper%
BlockInput On
SendInput ^{Enter}%finalwhisper%{Enter} ;<-- problem
BlockInput Off
return
}
So in the first line i am importing the value of custommessage1 (it could be "hi im henrik"). This is what i wish to end up getting as a output.
Inside the function i want the var (which is 1 in this case) to be merged with a variable called custommessage ending with a result of custommessage1
i want the endresult to do a SendInput %custommessage1%.
this way i can have one function for up to 9 triggers including var numbers.
Can anyone help? i am sure this is fairly simple however i am new to this coding thing so bear with me.
Your function only knows about its own variables, the ones you pass in as parameters, and global variables.
You're trying to access custommessage1, which is outside the function and isn't global. You either need to make all your variables global, or pass them in to the function.
I suggest the latter, using an array. Here's an example, make sure you're running the latest version of AHK for this to work properly.
IniRead, custommessage1, whisperconfig.ini, messages, Message1
IniRead, custommessage2, whisperconfig.ini, messages, Message2
; Store all messages in an array
messageArray := [custommessage1, custommessage2]
; Pass the array and message you want to print
^NumPad1::whispermessage(messageArray, 1)
whispermessage(array, index){
; Store the message at the given index in 'finalwhisper'
finalwhisper := array[index]
Msgbox, %finalwhisper% ; Test msgbox
; Print the message
BlockInput On
SendInput ^{Enter}%finalwhisper%{Enter}
BlockInput Off
}
Alternatively, and this is outside the scope of your question, you could load the keys from the .ini file dynamically, meaning you wouldn't have to create new variables each time you added a key/value pair.
Here's how you could do that:
; Read all the key/value pairs for this section
IniRead, keys, whisperconfig.ini, messages
Sort, keys ; Sort the keys so that they are in order
messageArray := [] ; Init array
; Loop over the key/value pairs and store all the values
Loop, Parse, keys, `n
{
; Trim of the key part, and only store the value
messageArray.insert(RegExReplace(A_LoopField, "^.+="))
}
; Pass the array and message you want to print
^NumPad1::whispermessage(messageArray, 1)
whispermessage(array, index){
; Store the message at the given index in 'finalwhisper'
finalwhisper := array[index]
Msgbox, %finalwhisper% ; Test msgbox
; Print the message
BlockInput On
SendInput ^{Enter}%finalwhisper%{Enter}
BlockInput Off
}

Using GetKeyState() and loops

I'm trying to write a script that has a loop in which the upper arrow key is pressed every two seconds. The loop must be activated when I press the spacebar and deactivated when I press it again. I'm now using this.
$Space::
if GetKeyState("Space", "P")
{
Loop
{
Sleep 2000
Send {Up}
if GetKeyState("Space", "P")
{
return
}
}
}
For some reason, the if condition inside the loop doesn't work, i.e. I can't get out of the loop. I hope anyone can help me out...
You wouldn't need the first if GetKeyState("Space", "P")
and you would need to be holding space when the loop got to the second one
for it to break; and you would need to replace the return with break.
However I agree with Gary, although I would write it like this:
; (on:=!on) reverses the value of variable 'on'
; the first press of space reverses on's value (nothing) to something (1)
; the second press reverses on's value from (1) to (0)
; when (on = 1) delay will be set to 2000, and Off when (on = 0)
space::SetTimer, Action, % (on:=!on) ? ("2000") : ("Off")
Action:
Send, {up}
Return
% starts an expression.
From http://l.autohotkey.net/docs/Variables.htm
?:
Ternary operator
This operator is a shorthand replacement for the if-else statement.
It evaluates the condition on its left side to determine
which of its two branches will become the final result.
For example, var := x>y ? 2 : 3 stores 2 in Var if x is greater than y; otherwise it stores 3.
How about using SetTimer?
; Create timer.
SetTimer, SendUp, 2000
; Set timer to 'Off' at start of script.
SetTimer, SendUp, Off
TimerEnabled := False
; When Space is pressed toggle the state of the timer.
$Space::
If TimerEnabled
{
SetTimer, SendUp, Off
TimerEnabled := False
}
Else
{
SetTimer, SendUp, On
TimerEnabled := True
}
; Label called by timer to send {Up} key.
SendUp:
Send, {Up}
return