Linguistic Alchemy to unlock AutoHotkey

A photorealistic image of a wizard performing linguistic alchemy, digital art.In the echoing halls of the Tower of Babel, myriad languages tangled, creating a confusion of tongues and leaving humans estranged.  Fast forward to the present day, professional translators stand as the modern-day heroes, bridging linguistic divides and fostering global connections.  Yet, these linguists often grapple with the technical juggernaut of AutoHotkey scripting.

AutoHotkey, an open-source scripting language, is a wizard in the realm of automation, turning mundane tasks into streamlined workflows on the Windows operating system.  For professional translators, however, the seemingly cryptic syntax and logic of these scripts can appear as a formidable dragon guarding a treasure trove of productivity.

Enter Artificial Intelligence (AI), the gallant knight on a silver steed, ready to slay the dragon and bridge the gap between the enchanting world of languages and the intricate realm of AutoHotkey scripts.  AI, with its intuitive understanding and predictive capabilities, can unravel the mysteries of scripting for those whose expertise lies in the art of languages rather than the science of code.

Think of AI as a bilingual interpreter, translating the complex language of scripts into something more approachable for translators.  This transformative synergy of AI and AutoHotkey scripting means that professional translators can now wield the power of scripting to automate their routine tasks, improve efficiency, and take their productivity to new heights, all without needing to dive deep into the technical intricacies of code.

So, dust off your language manuals, and polish your translator’s glasses.  The world of AutoHotkey scripting is about to unfurl its secrets under the guiding light of AI.  Let’s embark on this enchanting journey where languages meet scripts, and translators become scripters.  The tower of AutoHotkey scripting is no longer a place of confusion, but a beacon of possibility, thanks to the powerful ally of AI.

But where to start?  I’ve written about Autohotkey a few times in the past, most of the time keeping it fairly simple because I’m no Alchemist when it comes to working with this scripting language.  I also dabbled at using it for more complex things with the advent of AI,  and ChatGPT in particular, as I’ve found this remarkably good at making technology more accessible for everyone.  But if I’m honest I didn’t have a good usecase and no real will to persevere and make it work.  But then, thanks to the RWS Community a couple of weeks ago this all changed and the perfect opportunity reared it’s head with a great question… “Search & replace multiple words/terms in pre-translated segments?“.

In summary this is all about being able to take a list of search terms, with their replace equivalent, and run through them without having to do this manually one at a time.  There were a few desired features mentioned which I have tried to accommodate… this is what makes it interesting after all… so read the thread in full if you want to experience the full requirement.

So, now we have a topic what next?

Maintain thy essence, uncomplicated!

Simple alchemy imageOne thing I have learned when working with code is it sometimes helps to build things up slowly to ensure that ChatGPT has the right context, and you can also check things as you go along. So for this task I could start with asking this very simple question:

How do I go about using AutoHotkey to add some text into a search field and then click a replace all button?

The answer was simple enough..

#t:: ; This is the hotkey: Windows+T
Send, Your search text{Enter} ; Enter the search text and press Enter
Sleep, 100 ; Wait 100 milliseconds for the page to react
Send, {Tab} ; Move to the next field (Replace All button, in this case)
Sleep, 100 ; Wait again
Send, {Enter} ; Press the button
return

Something that I always like when working with ChatGPT is that the code is always well written with comments explaining what each line is doing.  So it’s a great learning tool even if it is doing the work for you.  For my tasks it seems to be using only line comments.  These are comments that last from the point they are declared until the end of the line.  This is done by using the semicolon ; character.  Everything after ; on the same line will be considered as a comment.  For example, the comment here would be “Press the button”:

Send, {Enter} ; Press the button

Simple enough, but I know in Trados Studio I’d need to press the tab key several times before pressing that button so now I have my next question.

How do you replicate pressing the tab 9 times

Now, I do know how to do this already… but the point is you can use this tool by building up your solution in a conversational style.  The answers are always helpful and ChatGPT never gets tired!

#t:: ; This is the hotkey: Windows+T
Send, {Tab 9} ; Press the Tab key nine times
return

It even provides additional, and helpful, information by explaining how to add a delay between each press of the Tab key in case the application you’re interacting with needs some time to process each Tab keystroke… which is often a problem for most applications operated by a script like this:

#t:: ; This is the hotkey: Windows+T
Loop, 9 ; Repeat the following commands 9 times
{
Send, {Tab} ; Press the Tab key
Sleep, 100 ; Wait for 100 milliseconds
}
return

So helpful and easy to follow so far… so let’s take it up a notch!

Escalating the Elixir of Eloquence

Screenshot showing a vase with a whispy alchemist like smoke.In this search & replace exercise (read the thread in the RWS Community) the search & replace terms are held in a tab delimited text file so I need to find a way of getting them out of here and into the search and replace fields in Trados Studio.  So I ask this question:

If I have a tab delimited text file containing multiple rows of text formatted like this:

search term tab target terms

How can I read the first row, run the script to search & replace, then loop back to enter the second row, run the script and repeat until I’m at the end of the file?

Note my skilful use of the English language to achieve what I need here 😉

ChatGPT obliges (improving my English question first!) and explains that if I want to read a tab-delimited text file line by line, extract the search and replace terms, and then perform some action based on those terms, I can use the FileReadLine command in AutoHotkey.  Assuming I have a text file named data.txt in the same directory as my script with rows formatted as search term [tab] target term, I could use a script similar to this one:

#t:: ; This is the hotkey: Windows+T
Loop, Read, data.txt ; Read the file line by line
{
StringSplit, line, A_LoopReadLine, `t ; Split the line into "line1" (search term) and "line2" (target term)
searchTerm := line1 ; Assign the search term
targetTerm := line2 ; Assign the target term

; Run your script here with the searchTerm and targetTerm
; Send, %searchTerm%{Enter} 
; Sleep, 100 
; Send, {Tab} 
; Sleep, 100 
; Send, %targetTerm%{Enter} 
; Sleep, 100 
; Send, {Tab 9} ; Press the Tab key nine times (or whatever is necessary)
; Sleep, 100 
; Send, {Enter} ; Press Enter to confirm the replace

}
return

This script reads the data.txt file line by line.  For each line, it splits the line into two parts: searchTerm and targetTerm, based on the tab character (designated by `t in AutoHotkey).  It then uses these terms in my search-and-replace commands.  The search and replace commands are commented out (; at the start of the line denotes a comment in AutoHotkey), so if you test this you’ll need to uncomment those and adapt them to your specific needs.  You’ll also need to replace “data.txt” with the path to the actual text file if it’s not in the same directory as your AutoHotkey script.

This of course gets me back to the original question in the forum of being able to select the search and replace file I want to work with.  So I step it up again…

I want to be prompted for the location of the text file every time I initiate this AHK script

The solution… I can use the FileSelectFile command in AutoHotkey to prompt for a file. Here’s how I might use it:

#t:: ; This is the hotkey: Windows+T

FileSelectFile, filePath ; Prompt the user to select a file
if filePath = ; If the user cancelled the file selection
return ; Exit the script

Loop, Read, %filePath% ; Read the selected file line by line
{
StringSplit, line, A_LoopReadLine, `t ; Split the line into "line1" (search term) and "line2" (target term)
searchTerm := line1 ; Assign the search term
targetTerm := line2 ; Assign the target term

; Run your script here with the searchTerm and targetTerm
; Send, %searchTerm%{Enter} 
; Sleep, 100 
; Send, {Tab} 
; Sleep, 100 
; Send, %targetTerm%{Enter} 
; Sleep, 100 
; Send, {Tab 9} ; Press the Tab key nine times (or whatever is necessary)
; Sleep, 100 
; Send, {Enter} ; Press Enter to confirm the replace
}
return

Like most things once I test this I want to improve it a bit more… so I ask this:

Can you amend this script below so that the selection of the file could be based on choosing from a dropdown list of files maintained in another settings file at a hardcoded location?

This way I can have a settings file where I save the paths to each file I might want to use and the dropdown list would list out the different files for me to select.  It also means I don’t have to keep updating the script, I just edit my settings file which will always be in the same location.

Naturally the solution is again so simple when you know how… although I did have a few attempts at this and ChatGPT reacted to my feedback correcting errors as it went… so that I eventually got here:

^!h:: ; The hotkey for Ctrl+Alt+H to start the process
Gui, Add, DropDownList, w500 vFilePath gStartReplace, Placeholder ; Add a dropdown list to the GUI with width of 500
Loop, Read, C:\hardcoded\path\to\settings.txt ; Read the hardcoded settings file line by line
{
GuiControl, , FilePath, %A_LoopReadLine%`n ; Add each line (file path) to the dropdown list
}
Gui, Show, , Select a file ; Show the GUI with the title "Select a file"
return

StartReplace:
Gui, Submit, NoHide ; Store the dropdown list's current selection in the variable filePath
Gui, Destroy ; Destroy the GUI

WinActivate, ahk_exe SDLTradosStudio.exe ; Activate SDL Trados Studio

Loop, Read, %filePath% ; Read the selected file line by line
{
StringSplit, line, A_LoopReadLine, `t ; Split the line into "line1" (search term) and "line2" (target term)
searchTerm := line1 ; Assign the search term
targetTerm := line2 ; Assign the target term

; Click in the "Find what" field
ControlClick, Edit2, ahk_exe SDLTradosStudio.exe
Sleep, 100
; Select all text and delete it
Send, {Home}+{End}{Del}
Sleep, 100
; Send the search term keystrokes
Send, {Text}%searchTerm%
Sleep, 100

; Click in the "Replace with" field
ControlClick, Edit1, ahk_exe SDLTradosStudio.exe
Sleep, 100
; Select all text and delete it
Send, {Home}+{End}{Del}
Sleep, 100
; Send the target term keystrokes
Send, {Text}%targetTerm%
Sleep, 100

; Click the "Replace All" button
ControlClick, WindowsForms10.BUTTON.app.0.ea119_r8_ad19, ahk_exe SDLTradosStudio.exe
Sleep, 100
}
return

By now of course I’m feeling pretty pleased with myself… even though I didn’t really do any of the work!  All I need now is some test data.

Forging the Philosopher’s Stones of Syntax

Philosophers stones...Throughout my career I’ve always enjoyed creating interesting sample data sets using anything from poetry written by Byron to scripts from Monty Python.  But it does take a little time, especially if it’s not just the text for translation.  But now I have ChatGPT!

I want to create a short set of test files to use this script you have prepared for me. Can you create three things:
First a short technical document in English about Generative AI and its usefulness in creating AutoHotkey Scripts
Next, a list of terms that would be in the technical document so I have a start for search & replace operations
Finally, a translation into French of the technical document.

I won’t bore you with the detail here, but suffice to say it obliged nicely and you’ll see this at the end when I demo the working script.

So now… is that it, am I complete?  No, of course not.  I have already made this article quite long but I wanted to emphasis how I have managed to achieve this so far without any real knowledge of how to script with AutoHotkey for anything more than some simple basics.  So let’s take a look at the “few” things left that I needed to tidy up and the few problems left to overcome.

Purifying the Philosopher’s Phrase

In this section I want to give you some idea of how I spent the full three hours or so trying to get this to work properly… but in shortened form:

  • display the name of the files in the list without the full path, and without the .txt extension in the dropdown list
  • after selecting the file I wanted the script ended and didn’t run through the search & replace operation
  • learned about using “ClassNN” to be more specific about how I select and use the controls in  windows application… so I could get away from pressing tab multiple times and simply select and use the button or field I needed
  • learned about Windows Spy to help with the us of ClassNN… more on this in the next section
  • I wanted to make sure that the drop down window appears in the same screen as the active application
  • check the paths I intended to use for my files and discovered special characters that can affect the correct working of the script (ampersand and diacritics for example)
  • learned how to debug in AutoHotkey by inserting message boxes after each step to see what is being returned (very simple!)
    ; Debug: print out the contents of the filePaths array
    for key, value in filePaths
    MsgBox, Key: %key%`nValue: %value%
  • the dropdown menu appeared behind the active application so I had to bring it forward
  • I wanted to display a message at the end of the search & replace operations so I knew for sure when the operation was complete… and put it on the same screen as everything else!
  • position the dropdown menu and the message box just above the find & replace window for Trados Studio… learned I need a custom GUI and not a message box if I need to position it somewhere specific!
  • increased the size of the text in by custom GUI’s ()message box and dropdown list
  • how to check the version of AutoHotkey I’m using with a short script:
    MsgBox % “AutoHotkey version: ” . A_AhkVersion
  • learned how different screens could impact the way an AutoHotKey script like this can be run so had to find find a way to identify where the centre of the screen I’m in is located before using coordinates to position my custom GUIs
  • learned how different computers could “name” the same ClassNN for the same application differently… so knowing how to use Windows Spy is essential

Hopefully you’ll see why I didn’t want to tell you about everything in detail… suffice to say I did all of this using simple English and interacting with ChatGPT in a conversational manner.  So I’d encourage you to try the same.  Once you take that first step there’ll be no stopping you!  But before you do you’ll almost certainly need to know a bit more about AutoHotkey Window Spy.

The Sorcerer’s Spyglass

In the last section I mentioned working with the controls for buttons and fields instead of using multiple presses of the tab key for example.  I did this to try and get a more consistent and accurate script.  This worked well for me but I soon learned later when another user tried to work with my script that the ClassNN name given to these controls can be different on a different machine, even with the same version of Trados Studio!  So I think it makes sense just to quickly show you how to use the Window Spy tool to check this for yourself.  It may even help you improve your own ability to write scripts if you didn’t know about this tool before.  Also worth noting I only learned about it as it came up in conversation with my AI friend and it (yes… he identifies as “it” or “assistant”) told me all about it!

Screenshot showing where you activate the Windows Spyglass application from a right-click on the AHK application.The AutoHotkey Window Spy, often referred to as “Window Spy,” is a tool that comes bundled with the AutoHotkey installation.  It provides you with detailed information about the active window and the elements within it.  This can be extremely helpful for scripting because it allows you to see specific information about window classes, titles, and even individual control elements in the application you are attempting to interact with.  For example it can provide you with this sort of thing:

  1. Basic Window Info:  This includes the window’s title, status, and process name (ahk_exe).
  2. Control Under Mouse Position:  This provides information about the specific control (an individual element of the GUI like a button or text field) that the mouse is currently over.  It includes details such as the control’s ClassNN, text, and position relative to both the window and the screen.
  3. Mouse Position:  This displays the current position of the mouse pointer relative to both the window and the screen.  It also provides the colour at the mouse cursor’s current position.
  4. Active Window Position:  This gives details about the size and position of the active window.

To access the Window Spy, right-click on the AutoHotkey icon in the system tray and select “Window Spy”.  Once it’s open, you can click on the windows or controls that you’re interested in, and it will display their information.

For example, in Trados Studio the “Replace All” button in the Find & Replace dialogue is like this:

Screenshot showing the Window Spy application when hovering over the "Replace All" key in Trados Studio. It's displaying the ClassNN.

To use it you need to do two things:

  1. make sure you check the box to “Follow Mouse”, and
  2. hover over the control you want to know the name for.

In this case for me, the ClassNN was “WindowsForms10.BUTTON.app.0.ea119_r8_ad19″.  But as you’ll see if you read the thread in the RWS Community it was “WindowsForms10.BUTTON.app.0.2eed1ca_r7_ad19″.  The difference is in the long alphanumeric string after app..  The r7 and r8 in each identifier might represent different versions or releases of the application, or they could represent different versions of the Windows Forms framework being used.  Similarly, 2eed1ca and ea119 could be identifiers for different instances of the same button within different versions or instances of the application, or again, they could represent different versions of the framework.

So something else I learned is that these identifiers are generated by the Windows Forms framework and could change across different computers, different application states, different application versions, and even different runtime environments.  Because these identifiers can be so variable and unpredictable, when writing scripts that automate interactions with Windows Forms applications, it’s often more reliable to interact with controls using other methods (such as by their text, if it’s consistent, or by their position in the window) rather than relying on the ClassNN identifiers.

In hindsight I should have used the “R&eplace All” text instead as it should be unique in this form, and if I do something like this again I will.  At the time I foolishly thought this nice long complicated ID would be the most unique thing to hook onto… just shows what I know!  Everything is a learning experience!

However… now you know about the Window Spy and I hope it’ll be useful for you too!

Inscribing the Immutable Incantation

Finally, here’s my final script that works for me, but may not work for you!  The things you need to check are these:

  1. the hardcoded path to my settings file in the script (line #)
  2. the ClassNN on your computer
  3. special characters in the paths to your files

But now you know how to check all that and fix it!  So here’s my script which as you can see has grown and grown.  It’s still a fraction of the code the Trados Studio developers have to work with and AutoHotkey is a lot more forgiving and easier to use.  I also haven’t added in all the checks and balances a professional developer has to think about… but I do think even this little exercise is a good introduction to the world of automation and programming, and it gives you an idea of how easy it is for things to break just for you when all is well for everyone else!

^!h:: ; The hotkey for Ctrl+Alt+H to start the process
global filePaths := {} ; Create an associative array to store full file paths
global fileNames := "" ; Create a variable to store the file names
global PosX, PosY ; Create global variables to store the dropdown menu's position

Gui, Add, DropDownList, w450 vFilePath ; Add a dropdown list to the GUI with width of 400
Gui, Font, s12 ; Set the font size to 12

Loop, Read, c:\AHK scripts\settings.txt ; Read the hardcoded settings file line by line
{
    SplitPath, A_LoopReadLine, name, dir, ext, name_no_ext, drive ; Split the file path into parts
    fileNames .= name_no_ext . "|" ; Add the file name (without extension) to the string, separated by "|"
    filePaths[name_no_ext] := A_LoopReadLine ; Store the full file path in the associative array
}

fileNames := SubStr(fileNames, 1, StrLen(fileNames) - 1) ; Remove the last "|"
GuiControl,, FilePath, %fileNames% ; Set the items of the dropdown list

WinGetPos, PosX, PosY, Width, Height, A ; Get the position and size of the active window
SysGet, Monitor, MonitorWorkArea, % "Monitor" . ((PosX + Width / 2) // (A_ScreenWidth / A_ScreenCount) + 1) ; Get the work area of the monitor where the window's center is located
if (PosX < MonitorLeft)
    PosX := MonitorLeft
else if (PosX > MonitorRight - 500) ; 500 is the width of the GUIs
    PosX := MonitorRight - 500
if (PosY < MonitorTop)
    PosY := MonitorTop
else if (PosY > MonitorBottom - 100) ; 100 is the height of the GUIs
    PosY := MonitorBottom - 100
PosY := PosY - 150 ; Subtract 150 from PosY
Gui, Show, x%PosX% y%PosY% w500 h100, Select a file ; Show the GUI at the position of the active window with a larger window
WinSet, AlwaysOnTop, On, A ; Make the GUI always stay on top of other windows
return

GuiClose: ; When the GUI is closed
Gui, Submit, NoHide ; Store the dropdown list's current selection in the variable filePath
filePath := filePaths[filePath] ; Retrieve the full file path from the associative array
Gui, Destroy ; Destroy the GUI
GoSub, StartReplace ; Continue with the search and replace operation
return

StartReplace:
WinActivate, ahk_exe SDLTradosStudio.exe ; Activate SDL Trados Studio

Loop, Read, %filePath% ; Read the selected file line by line
{
    StringSplit, line, A_LoopReadLine, `t ; Split the line into "line1" (search term) and "line2" (target term)
    searchTerm := line1 ; Assign the search term
    targetTerm := line2 ; Assign the target term

    ; Click in the "Find what" field
    ControlClick, Edit2, ahk_exe SDLTradosStudio.exe
    Sleep, 100
    ; Select all text and delete it
    Send, {Home}+{End}{Del}
    Sleep, 100
    ; Send the search term keystrokes
    Send, {Text}%searchTerm%
    Sleep, 100

    ; Click in the "Replace with" field
    ControlClick, Edit1, ahk_exe SDLTradosStudio.exe
    Sleep, 100
    ; Select all text and delete it
    Send, {Home}+{End}{Del}
    Sleep, 100
    ; Send the target term keystrokes
    Send, {Text}%targetTerm%
    Sleep, 100

    ; Click the "Replace All" button
    ControlClick, WindowsForms10.BUTTON.app.0.ea119_r8_ad19, ahk_exe SDLTradosStudio.exe
    Sleep, 100
}

; PosY := PosY - 150 ; Subtract 150 from PosY
Gui, 2:New, +AlwaysOnTop ; Create a new GUI for our custom message box
Gui, 2:Font, s12 ; Set the font size to 12
Gui, 2:Add, Text, w500 h50, The search and replace operation is complete. ; Add a text element to the GUI
Gui, 2:Show, x%PosX% y%PosY% w500 h100, Operation Complete ; Show the GUI at the position of the dropdown menu with the title "Operation Complete"

Sleep, 500 ; Wait for 500 milliseconds (half a second)
WinActivate, Operation Complete ; Activate the GUI window using its unique title

return

2GuiClose: ; When the custom message box is closed
Gui, 2:Destroy ; Destroy the GUI
return

And here’s how it works in practice!

9 thoughts on “Linguistic Alchemy to unlock AutoHotkey

  1. As always, great read, Paul! Very glad to have provided the inspiration for this post. I wonder if there’s a way to make this scrit work not only with single words, but also with terms made of multiple words. Of course, I can always ask ChatGPT, but I still have more faith in humans… for the time being 😉

  2. Me again! I’m taking back my earlier reply. The script does work with terms made of multiple words. But for me I just found out that at one point (after maybe 7 or 8 replacements) it just stops making further replacements and leaves target terms unchanged, even though they’re on the replacements list. Odd.

      1. Interesting. Will definitely give that a try. In the meantime, I found a workaround by splitting the replacements list in two and process the two parts one after the other.

  3. Cool! I’ve also been playing around with ChatGPT a lot and have created all kinds of useful little AutoHotkey and Python scripts to do things in my daily work life. I’m definitely no programmer, but have already learnt loads with the help of ChatGPT.

    I have little Python scripts to extract data from multilingual dictionaries in PDF form, all kinds of little AHK scripts to automate stuff on my computer, and most interestingly/usefully (for me at least) is something I am working on called ‘Beijer.bot’. This is a visual dashboard providing centralised access to many little tools I use when translating. The individual items are grouped into categories like Text actions, Web searches, Bookmarks, Passwords, etc. The individual items can be accessed through various interaction modalities, such as clicking on menu items, using keyboard shortcuts or even voice commands (powered by Talon Voice, my Dragon replacement). For more information on, see Beijer.bot. I also made a very quick video and stuck it here: https://www.youtube.com/watch?v=08lysAyrD14

  4. PS: I’m not sure if you’re having the same problem, but do you also find it absolutely impossible to get ChatGPT to give you AHK v2 code? No matter how many times I ask it, or how I ask it, it simply keeps giving me v1 code, and apologizing profusely each time, and then proceeding to make the same exact mistake over and. I’m assuming that’s because the training data doesn’t contain much v2 code.

    1. When I have played with AHK I did indeed have this problem so where needed I had to figure out how to manage the differences myself… not a bad exercise really as it becomes almost too easy otherwise and you never really learn unless you’re very diligent. I haven’t done a lot with AHK, but have done with VB, Python and Powershell… all where ChatGPT really does help you get over any initial barriers to even getting started!

Leave a Reply