How can I use a variable as a key in the associative array in autohotkey? - autohotkey

In autohotkey_L, there is a associative data structure. For example,
hash := {key_hash:"value"}
val:= hash["key_hash"]
MsgBox %val%
But if I want to use a variable as a key to access the value in the assocative array, it fails. For example, the following doesn't work
hash := {key_hash:"value"}
other_val="key_hash"
val:= hash[other_val]
MsgBox %val%
and this doesn't work either:
hash := {key_hash:"value"}
other_val="key_hash"
val:= hash[%other_val%]
MsgBox %val%
** gave me an error: The following variable name contains an illegal character: ""key_hash""
How can I use a variable to access the value in an associative array?
I need this to get the key as an argument in a function.

Alby,
Your variable other_val contained the data: "key_hash" , not what you wanted: key_hash. Just remove the two double quotes and you are fine.
hash := {key_hash:"value"}
other_val=key_hash
val:= hash[other_val]
MsgBox %val%

Or use the assignment (:=)
hash:={key_hash:"value"} ; hash:=Object("key_hash", "value")
other_val:="key_hash"
val:=hash[other_val]
MsgBox, % val

Related

Autohotkey / AHK - Param %1% not accessible within a function

I'm having a problem with accessing the %1% ( Startup Param that has been passed to the Script by the console ) in Autohotkey.
When I use the following code (outside of a function):
Msgbox %1%
I get the output of the Param that has been passed to the Script. But as soon as I use the following Code:
HelloWorld() {
Msgbox %1%
}
HelloWorld()
The output is empty.
I also tried to assign %1% to a global variable, or to pass it to the Function as a parameter but it didn't work for me neither.
Thank you
I believe the command line parameter variables are considered global variables, so in order to use them in a non-expression context inside a function you have to declare them as global:
HelloWorld() {
global 1
Msgbox %1%
}
HelloWorld()
It gets even more confusing once you want to use them in expressions (such as using % in the text argument for MsgBox), since they will be treated as numbers so you have to indirectly access them through variables:
HelloWorld() {
;global 1
; Neither of these two expressions access the variable named "1"
;Msgbox % 1
;Msgbox % %1%
; You have to do this instead:
p := 1
MsgBox % %p% ; p is translated to 1 and then "1" is used as a variable name
}
HelloWorld()
Note that doing this doesn't require global 1.
If you're using the newest version of AHK, you instead probably want to use the newly introduced built-in variable A_Args, which is an array that holds the command line parameters. Being built-in, it doesn't have to be declared global, and it ultimately makes the code clearer:
HelloWorld() {
MsgBox % "Number of command line args received: " A_Args.Length() "`n"
. "First argument: " A_Args[1]
}
HelloWorld()
Just declare your cli variables as Global - outside the function - to make them globally available to any and all internal functions. For me, this is how I do it with my version of AHK (Version 1.1.25.01):
Global 1, 2, 3
HelloWorld() {
MsgBox Hello`t1:`t%1%`n`t2:`t%2%`n`t3:`t%3%
}
HelloWorld()
Note, these are different command lines:
"Scripts\myScript.ahk" one two three
"Scripts\myScript.ahk" "one two" three
"Scripts\myScript.ahk" "one" "two three"
"Scripts\myScript.ahk" "one two three"
The first is three separate parameters, the second and third, only two and the last is only one param (2 and 3 exist, but are empty).
Hth,

Is it possible to initialize array in batch in AutoHotKey?

I know I can write
a := Object()
a[1] := "textA"
a[2] := "textB"
a[3] := "textC"
Can I write something like
a := {"textA", "textB", "textC"}
?
You can define an indexed array using the bracket syntax:
a := ["textA", "textB", "textC"]
or the array creation function:
a := Array{"textA", "textB", "textC"}
An indexed array is an object representing a list of items, numbered 1 and up. In this example, the value "textA" is stored in object key 1, the value "textB" in object key 2 and the value "textC" in object key 3.
https://autohotkey.com/docs/Tutorial.htm#s7

How do I use the contents of an array as a variable name?

Currently I store the contents of an array into a variable, then set that variable up using two % and store a value. My current code looks like this:
Test := {asdf: "blah"}
Temp := Test["asdf"]
%Temp% := "boo"
; above line is be the same as blah := "boo", but blah came from a variable
msgbox %blah% ; outputs "boo"
I don't like having to use the Temp variable like this.
The following compiles but blah stays blank:
(Test["asdf"]) := "boo"
%Test%["asdf"] := "boo"
The following gives me a compile error:
%(Test["asdf"])% := "boo"
I have a vague idea that it should be possible but I just can't find the syntax for it. How do I directly use the array instead of having to put it in a temp variable?
Just figured it out.
The problem here is creating variables using dynamic data may cause invalid variable names to be created. All sorts of ways to screw up here (spaces, UTF-8 code, etc).
One safer way is to use Associative Arrays:
Output := Object()
Test := {asdf: "blah"}
Output[(Test["asdf"])] := "boo"
msgbox % Output["blah"]
There are less restrictions on keys than variable names.
globalWrapper(NameOfTheGlobalVar, LocalVar) {
global
%NameOfTheGlobalVar% := LocalVar
}
Test := {asdf: "blah"}
globalWrapper(Test["asdf"], "boo")
msgbox %blah% ; outputs "boo"

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
}

Global variable does not have global scope

supposedlyGlobalVariable := "blah"
ARoutine()
{
localVariable := "asdf"
MsgBox, The global variable value is %supposedlyGlobalVariable%. The local variable value is %localVariable%.
}
^!X:: ;This assigns the hotkey CTRL + ALT + X to run the routine
ARoutine()
return
Run the code and the result is:
"The global variable value is . The local variable value is asdf."
The documentation states:
Variable scope and declarations: With the exception of local variables
in functions, all variables are global; that is, their contents may be
read or altered by any part of the script.
Why does my global variable not have scope within the function?
The documentation for global variables can be found here:
https://autohotkey.com/docs/Functions.htm#Global
Global variables
To refer to an existing global variable inside a function (or create a
new one), declare the variable as global prior to using it. For
example:
LogToFile(TextToLog)
{
global LogFileName
FileAppend, %TextToLog%`n, %LogFileName%
}
I believe the concept of global, with AHK, is a bit different than in other languages. With AHK you can create a variable and use it within multiple hotkeys, and subroutines, without declaring it as global.
Gv := 0
f1::SetTimer, Action, % (on:=!on) ? (1000) : ("Off")
Action:
Gv++
trayTip,, % Gv
Return
f2::Msgbox, % Gv
Explaination of code:
The F1 key toggles a timer to run the subroutine: Action every 1000ms.
% starts an expression.
on:=!on reverses the binary value of variable on every time F1 is pressed.
?: together is called the ternary operator.
When on=1 delay is set to 1000ms; when on=0 the timer is turned Off.
The ++ operator adds 1 to variable Gv.
This makes things easier:
https://www.autohotkey.com/docs/Functions.htm#SuperGlobal
Super-global variables [v1.1.05+]: If a global declaration appears
outside of any function, it takes effect for all functions by default
(excluding force-local functions). This avoids the need to redeclare
the variable in each function. However, if a function parameter or
local variable with the same name is declared, it takes precedence
over the global variable. Variables created by the class keyword are
also super-global.
Just declare your variable as global in the main script:
global supposedlyGlobalVariable := "blah"
P.Brian, It works when you do this.. I know it doesn't explain why, but this might be your workaround.
#Persistent
GlobalVariable = "blah"
RETURN
ARoutine:
{
localVariable := "asdf"
MsgBox, The global variable value is %GlobalVariable%. The local variable value is %localVariable%.
}
Return
^!X:: ;This assigns the hotkey CTRL + ALT + X to run the routine
gosub, ARoutine
return
You just need to declare the variable as global inside your function
supposedlyGlobalVariable := "blah"
ARoutine()
{
global supposedlyGlobalVariable
localVariable := "asdf"
MsgBox, The global variable value is %supposedlyGlobalVariable%. The local variable
value is %localVariable%.
}
^!X:: ;This assigns the hotkey CTRL + ALT + X to run the routine
ARoutine()
return