Setting a control name with concatenated text+variable for ControlSetText usage - autohotkey

TL;DR I created a new variable (destinationControl) by concatenating a string, a separate string variable, and then another string. I tried using the variable destinationControl with ControlSetText, but its not working. Can anyone tell me why?
Long Explanation:
I'm attempting to send some data from an excel spreadsheet into another application using AHK ControlSetText. My issue comes in when I need the script to detect which one of two possible programs is the active one (the detection part is working) and then based on the name of the program, set the destination control name is slightly different.
prog_A_segment := "abc"
prog_B_segment := "def"
;determine which program is open
IfInString, OpenProgram, ProgA
{
ctrlSegment := prog_A_segment
}
else
ctrlSegment := prog_B_segment
;set control variable
destinationControl := "WindowsForms10.EDIT.app.0." . ctrlSegment . "_r13_ad11"
;activate program
WinActivate, % OpenProgram
WinWaitActive, % OpenProgram,,3
;open vendor form
Sleep 300
Send ^o
Sleep 200
Send Vendors
sleep 200
Send {ENTER}
Sleep 2000
;This does not work:
;pass information to vendor form control
ControlSetText, %destinationControl%, %myNumber%, %OpenProgram%
I know I could just slightly more manually set them based on the open program but i have about 25 controls in total and the only difference is that center segment so I thought this would be a little more elegant and cleaner.
When I use the above method it doesn't appear AHK can find the control. I'm assuming it has something to do with how I combined a string and a variable. Is there some way to make this approach work without doing this instead:
IfInString, OpenProgram, ProgA
{
destinationControl1 := "WindowsForms10.EDIT.app.0.abc_r13_ad11"
....
destinationControl25 := "WindowsForms10.EDIT.app.0.abc_d52_ad11"
}
else
destinationControl1 := "WindowsForms10.EDIT.app.0.def_r13_ad11"
....
destinationControl25 := "WindowsForms10.EDIT.app.0.def_d52_ad11"

I agree with Josh Brobst that your first piece of code would work with the missing quote added.
Well, here's what you want to try anyways:
ctrlSegment := InStr(OpenProgram, ProgA) ? "abc" : "def"
Loop Parse, % "r13, ... ,d52", CSV
ControlSetText % "WindowsForms10.EDIT.app.0." ctrlSegment "_" A_LoopField "_ad11"
, % myNumber, % OpenProgram

Related

AutoHotKey if clipboard contains in array value

I am making a script for validating wallet cryptocurrency.
so whenever I copy the address wallet and then I run the script. if the address wallet same as the array value, it will show msgbox that give information about the wallet name. if not it will show n/a.
but I have some problems, where the msgbox shows based many numbers of the array
here is my code
^q::
walletAddr := Object("wallet1", "0x01415e36ce36d07229abf8b0435669088319f656", "wallet2", "0x9d6fb140607e1727c1373624a97ba681ef54f5bk", "wallet3", "0x660f01a47efd305862bc598cad44d1966b376d67")
found := 0
for k, v in walletAddr
if ( clipboard == v ) {
MsgBox % k
found := 1
}
if !found
MsgBox, n/a
return
and I figure out that this problem isn't from the script. but from the array value.
I try to change the value to a simple word and it works perfectly
walletAddr := Object("wallet1", 0xFF0000, "wallet2", 0x0000FF,"wallet3", 0x00FF00)
I have no clue where the problems come from. maybe it's because of length value, value typedata, or others.
can someone help me figure out my problem? thank you
i found tricky way to make it work :D
just add string text ( i use = "wallet_" ) before value and before clipboard.

AutoHotkey - send hotkeys to nested folders

Using Autohotkey, I can send "ctrl+" to Windows File Explorer, to auto adjust column width.
Manually, it's ctrl+ (the + in the numpad).
This code below works, but only for first level folders, not if I open a folder within a folder.
Is there a way to send "ctrl+" again for each subfolders I might open?
Gui, +LastFound
DllCall("RegisterShellHookWindow", UInt, WinExist())
MsgNum := DllCall("RegisterWindowMessage", Str, "SHELLHOOK")
OnMessage(MsgNum, "ShellMessage")
Return
ShellMessage(wParam, lParam) {
wTitle = ahk_id %lParam%
WinGet, pname, ProcessName, %wTitle%
If (wParam != 1 || pname != "Explorer.exe")
Return
WinActivate, %wTitle%
Send ^{NumpadAdd} ;ctrl+ (numpad)
}
Seems like a pretty questionable approach.
I would rather see about somehow setting this to be the default behavior, or automating this with COM instead of sending a hotkey.
Anyway, for the hotkey approach, this seems to do the trick:
;No need to create a gui, A_ScriptHwnd is used for this
DllCall("RegisterShellHookWindow", UInt, A_ScriptHwnd)
MsgNum := DllCall("RegisterWindowMessage", Str, "SHELLHOOK")
OnMessage(MsgNum, "ShellMessage")
Return
ShellMessage(wParam, lParam)
{
static _time := 0
if (wParam = 6 && A_TickCount - _time > 100 && WinActive("A") = lParam)
{
_time := A_TickCount
WinGet, pname, ProcessName, % "ahk_id " lParam
if (pname = "explorer.exe")
{
ControlFocus, DirectUIHWND2, % "ahk_id " lParam
SendInput, ^{NumpadAdd}
}
}
}
So, first ditched the legacy way of getting a hwnd for the current script, and used A_ScriptHwnd (docs).
Also, ditched legacy syntax overall.
Then switched over to the HSHELL_REDRAW (docs) event to check for window title changes.
And the timing stuff is to filter out duplicate shell messages. When the title changes, we actually receive like 10+ of those messages at once. Only need to run the hotkey once.
So a simple 100ms cooldown does the trick.
A_TickCount (docs) is used for this.
Also made the checking order smarter.
No need to get the process name if we didn't even receive the correct shell message.
And finally before sending the hotkey, activate the correct control so the hotkey will work. This part is likely going to be wrong for you if you're on some older or future Windows version.
Also switched over to SendInput (docs) due to it being the recommended faster and more reliable send mode.

Get First Character of A_LoopFileName?

I'm trying to parse a filename and get the first character from it as a string to compare it to a previously inputted variable. My code looks like:
FileSelectFolder, WhichFolder ; Ask the user to pick a folder.
; Ask what letter you want to start the loop from
InputBox, UserInput, Start At What Letter?, Please enter a letter to start at within the folder (CAPITALIZE IT!)., , 450, 150
if ErrorLevel {
MsgBox, CANCEL was pressed.
ExitApp
} else {
inputted_letter = %UserInput%
tooltip %inputted_letter% ; Show the inputted letter
sleep, 2000
tooltip
}
Loop, %WhichFolder%\*.*
{
current_filename_full = %A_LoopFileName%
files_first_letter := SubStr(current_filename_full, 1, 1)
tooltip %files_first_letter% ; Show the file's first letter
sleep, 2000
tooltip
if files_first_letter != inputted_letter
continue
...
Right now, it clearly shows in the tooltips the user-entered capital letter, and then the first letter of each file name from within the selected folder, but for some reason when the two look alike, it doesn't recognize them as a match. I'm thinking maybe because technically A_LoopFileName is not of a string type? Or maybe the inputted letter doesn't match the type of the first filename's letter?
I want it to continue if the inputted letter and the first letter of the filename don't match, but if they do, to carry on with the rest of the script. Any ideas on how I can get these two to successfully match? Thanks!
Firstly, AHK doesn't really have types. At least not how you've experienced types in other languages.
So your assumption about "not being correct type" will pretty much always be wrong.
So the actual cause is because in a legacy if statement, the syntax is
if <name of variable> <operator> <legacy way of representing a value>
So you'd do it like this:
if files_first_letter != %inputted_letter%
You we're comparing if the variable files_first_letter is equal to the literal text inputted_letter.
However, I highly recommend you stop using legacy syntax. It's really just that old.
It'll differ horribly much from any other programming language and you run into confusing behavior like this. Expression syntax is what you want to use in AHK nowadays.
Here's your code snippet converted over to expression syntax in case you're interested:
FileSelectFolder, WhichFolder
;Forcing an expression like this with % in every parameter
;is really not needed of course, and could be considered
;excessive, but I'm doing it for demonstrational
;purposes here. Putting everything in expression syntax.
;also, not gonna lie, I always do it myself haha
InputBox, UserInput, % "Start At What Letter?", % "Please enter a letter to start at within the folder (CAPITALIZE IT!).", , 450, 150
if (ErrorLevel)
;braces indicate an expression and the non-legacy if statement
;more about this, as an expression, ErrorLevel here holds the value
;1, which gets evaluated to true, so we're doing
;if (true), which is true
{
MsgBox, % "CANCEL was pressed."
ExitApp
}
else
inputted_letter := UserInput ; = is never used, always :=
Loop, Files, % WhichFolder "\*.*"
;non-legacy file loop
;note that here forcing the expression statement
;with % is actually very much needed
{
current_filename_full := A_LoopFileName
files_first_letter := SubStr(current_filename_full, 1, 1)
if (files_first_letter != inputted_letter)
continue
}
Also you don't have to be concerned about case with !=, it'll always compare case insensitively.

AutoHotKey: Loop thru Associative Array

Happy to be back in the forums!
So after some extensive searching both in the AHK documentation, stackexchange and the ahk_forum, I have decided to seek help from the experts
I will explain the code I am working on and then post some examples.
I have written a script that pulls the value of untranslated and unverified words of 6 different word files and does this for 23 different languages via WebTranslateIt (site). I have managed to get it to work by coping the block of code and setting the "fileid" variable to one of the 6 files before each new query, however when I arrived at the language iteration part, I quickly noticed it would be a lot more efficient (and significantly less code) to simply have one loop within a loop iterate through two arrays until end of array.
This script accesses a website using Google Chrome, then proceeds to inject several jQueries into the developer tools and extract the results into independently named variables (which I would like to assign as part of an associate array).
This is the part that I am having issues with... I can loop through an array succesfully via:
langid := ["bg", "cs", "da", "el", "eu", "fi", "hr" , "ja", "ko", "lt", "nb",
"nl", "pl", "pt", "ro" , "ru", "sk", "sl", "sv", "th" , "tr", "zh", "zh-Hant"]
For Key, Value in langid
; MsgBox, %A_Index% = %Value% ; the MsgBox displays index values correctly but when putting my script in a loop start after the For Key part, it does not provide a value when sending the var inside a url. This works fine when I set the var manually before sending the URL.
But when I tried running this right before Looping the script that does the main querying, the 'langid' variable in the URL I send to change the language is blank.
I would like to loop the script 23 times through all the languages. When the script enters the loop there is a part that enters page URL with a %langid% and I cannot get this part to work with the above code.
Further to this, I would also like to assign further values to each key in the index as follows:
langid := ["bg", "cs", "da", "el", "eu", "fi", "hr" , "ja", "ko", "lt", "nb",
"nl", "pl", "pt", "ro" , "ru", "sk", "sl", "sv", "th" , "tr", "zh", "zh-Hant"]
lang := ["Bulgarian", "Czech", "Danish", "Greek", "Basque", "Finnish",
"Hungarian", "Japanese", "Korean", "Lithuanian", "Norwegian", "Dutch",
"Polish", "Portuguese", "Romanian", "Russian"]
The 'lang' array should reference the index position in 'langid', as I use it as a descriptive variable in some MsgBoxes that show word count progress and a function at the end that writes the total results of the 6 files per language. (This is purely aesthetic but I would love to get it working in the loop)
I also need something very similar with the wordfiles:
filenum := ["342553", "342582", "342411", "342367", "342467", "342502"]
wrdfile := ["OHFrontend", "OHFrontendListing", "HouseTypeAndSubType", "GuestType", "RoomTypeFeatureName", "RoomTypeFaturePrefixAndBracketOption"]
The 'wrdfile' array is also purely aesthetic, as I rather display the filename and not filenum in the totals confirmations. The 'filenum' however IS important and needs to iterate through each value in the array once until arriving at the end, at which point it needs to restart but with the next language in the 'lang' array.
I am thinking the following structure would work:
langid := [val1, val2, etc..]
lang := [val1, val2, etc..]
For Key, Value in langid ; iterate through Languages
Loop
{
filenum := [val1, val2, etc...]
wrdfile := [val1, val2, etc...]
Run Chrome
Open Site
For Key, Value in filenum ;iterate through Wordfiles
Loop
{
Send URL containing 'langid' var & 'filenum' var
Open DevTools and send jQuery and store totals
Confirm totals in MsgBox and save in txt file
}
Return
It is worth noting that all languages need to iterate through the same 6 wordfiles, so perhaps the file array can also be part of the first associative array instead of two different ones...? Not sure what is the best approach here.
Please help me me find the correct structure and syntax for the loops and if possible point me in the right direction as far as the arrays go. (I know I am not associating them correctly)
I need assistance with forming associative arrays... the documentation and examples I´ve looked up is not thorough enough. Please help atleast with a push in the right direction :oops:
I need assistance with the For Key command. It should go through the loop underneath it serving up the next 'langid' value on each iteration until the last value ("zh-Hant").
Once I have point 2 working then I will tweak the script to also loop through the 6 wordfiles and then reiterate language. My intention is to loop through the 6 wordsfile for each language. Once that is working I will add a small GUI prompt to enable going through the entire loop or just through a specific language.
Link to AHK_Forum post containing full code.
THANKS AGAIN!
You could use an associative array for your language and files variables. The correct syntax for associative arrays is as follows.
object := { "key1" : "value", "key2" : "value 2" }
You can iterate over the array with a for loop like so.
for key, value in object
MsgBox key: %key% value: %value%
The for loop already iterates through your object so you don't need the loop beneath it. If I'm understanding you correctly you could try something like this.
; Associative arrays
Langs := { "bg" : "Bulgarian", "cs" : "Czech" }
Files := { "342553" : "OHFrontend", "342582" : "OHFrontendListing"}
; Open Chrome
For langId, langName in Langs
{
For fileId, fileName in Files
{
url := "example.com/" . langId . "/" . fileId
; Send url with langId & fileId
; Open DevTools and send jQuery and store totals
; Confirm totals in MsgBox and save in txt file
msgbox %url%
}
}
Return

How to pass window title to user function in AutoHotKey

I want to pass the window title into a function I wrote in AutoHotKey, is window title WinTitle a string? I have 4 window titles, and I need to pass them to the same function.
Extract(my_window_title) {
; Wake and select the correct window to be in focus
WinWait, my_window_title,
IfWinNotActive, my_window_title, , WinActivate, my_window_title,
WinWaitActive, my_window_title,
; ... do a bunch of things
}
I call the function like this
title1 = "Some title"
Extract(title1)
and I also tried putting % in all the variables
Yes WinTitle is basically a string.
Check out your Autohotkey-folder, there should be a file called "AU3_Spy.exe". Use it to find the window titles.
And as Elliot DeNolf already mentioned, you made some mistakes with variables. You should also take another look at the syntax of IfWInNotActive.
This should work:
Extract(my_window_title) {
; Wake and select the correct window to be in focus
WinWait, %my_window_title%
IfWinNotActive, %my_window_title%
{
WinActivate, %my_window_title%
WinWaitActive, %my_window_title%
}
msgbox, %my_window_title%
; ... do a bunch of things
}
title1 = MyWindowTitle
Extract(title1) ;functions always expect variables, no percent-signs here
There are a few things that look like they are causing an issue in your script.
When assigning a string value and using =, quotes are not needed. If you assign the value using :=, then you need the quotes. These 2 lines are equivalent:
title1 := "Some Title"
title1 = Some Title
Once these values are called via a function ie. Extract(title1), % symbols must be used (as you mentioned at the end of your question). This can be called in 2 ways:
WinActivate, %my_window_title%
WinActivate, % my_window_title
If the title is invalid, your script will wait indefinitely on WinWait and WinWaitActive. I would recommend using a timeout value and then checking ErrorLevel to see if it was successful or not.