Need help converting AHK script to Autokey.

272 views
Skip to first unread message

varg

unread,
May 15, 2023, 4:45:15 PM5/15/23
to autokey-users
Hi,

I'm a fairly new Autokey user and use it for phrases. But my colleague showed me his AutoHotKey script that he uses for work and I really want to convert it so it'll function with Autokey on Arch Linux. I've tried doing this by myself, with help of Google, ChatGPT and other Autokey users. But I've realized that my skill level is not what it needs to be, and I'll never manage to create something equivalent for Autokey.

So, I'm hoping someone could help me with this. At this point I'm ready to pay for the trouble.

PS. I've almost decided to go back to Windows just so I can use this script lol. I don't wanna do that, so pls help

Thanks in advance

#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.

#Include <Rufaydium>

/*
************ Initial variable set-up ************
*/

GappUser = @example.com
GappPassword =
sudoUser = baba
sudoPassword =
sudoPutty =
sudoKeyFile =

FireFoxPath = C:\Program Files\Mozilla Firefox\firefox.exe

/*
******************* Hotstrings *******************
*/

<^>!p:: ; Password (sudo)
SendRaw %sudoPassword%
return

<^>![:: ; Password (putty)
SendRaw %sudoPutty%
return

/*
*** User data ***
*/

<^>!o:: ; User SSH password "o" as next to "P"assword
SendRaw %proxySSH%
return

<^>!u:: ; Username
SendRaw %uname%
return

<^>!y:: ; Servername "y" as next to "u"sername
SendRaw %sname%
return


/*
****************** Ctrl Hotkeys ******************
*/


^0:: ; Load customer data

; Exit Firefox not active
;if NOT isFireFoxActive()
; return

; Exit if user and servername not selected
uname := UserName()
sname := ServerName()
If !uname or !sname
return

; Connect to Chrome
Browser := new Rufaydium()
Page := Browser.NewSession()
; WinID := WinExist("A")

; Gapp Login
Page.Navigate("https://example.com/login/")
Page.Navigate("https://example.com/login/")
Page.querySelector("#id_username").value := GappUser
Page.querySelector("#id_password").value := GappPassword
Page.querySelector(".btn-info").click()

; Gapp User Proxy
Page.Navigate("https://example.com/service/?q=" uname "+" sname)
; sleep 500
proxyEmail := Page.querySelector(".field-user").children
proxyEmail := html_decode(proxyEmail[0].innerHTML)
proxyUsername := html_decode(Page.querySelector(".field-username").innerHTML)
proxyUser := html_decode(Page.querySelector(".field-user__id").innerHTML)
proxySSH := html_decode(Page.querySelector(".field-shell_password").innerHTML)

; Load Proxy User Control Panel - https://example.com/control
Page.querySelector(".form-control[name=Nickname]").value := "" ; shouldn't be needed, but is!
Page.querySelector(".form-control[name=Nickname]").value := proxyUser
Page.querySelector(".btn").click()
Send, ^r
Sleep 500

/*
; Load Proxy User Control Panel - https://example.com/control
Page.querySelector(".form-control[name=email]").value := "" ; shouldn't be needed, but is!
Page.querySelector(".form-control[name=email]").value := proxyEmail
Page.querySelector(".btn").click()
uid := Page.getElementById("userId").innerHTML
MsgBox %uid%
*/
Browser.QuitAllSessions()
Page :=
Browser :=

return

^1:: ; Load Meter Client page

if isFireFoxActive()
{
Send, ^t
Send, https://example.com/sadmin/clients.php?email=%proxyEmail%{Enter}
}
return

^2:: ; Load Gapp Services page
if isFireFoxActive()
{
Send, ^t
if proxyEmail
Send, https://example.com/service/?q=%proxyEmail%{Enter}
else
Send, https://example.com/service/?q=%uname% + %sname%{Enter}
}
return

^3:: ; Load proxy Control Panel
if isFireFoxActive()
{
Send, ^t
Send, https://example.com/control/#/{Enter}
}
return

^4:: ; Load (user) account ssh
; SSH - PuTTY into Customer account
Run, "C:\Program Files\PuTTY\putty.exe" %sname%.abc.com -l %uname% -pw "%proxySSH%"
return

^5:: ; Load (server) staff account ssh
; SSH - PuTTY into Customer account
Run, "C:\Program Files\PuTTY\putty.exe" %sname%.abc.com -l %sudoUser% -i %sudoKeyFile%
return

^7:: ; Latest Transfer Set-up

; Exit Firefox not active
if NOT isFireFoxActive()
return

sids := GetServiceIDs()

if sids
for k, sid in sids
{
Send, ^#d
Sleep, 200
Run, %FireFoxpath%
Sleep, 2000
Send, https://example.com/sadmin/clientsservices.php?id=%sid%{Enter}
Sleep, 5000
Send, {tab 40}
Sleep, 1000
Send, ^{enter}
}
return

^8::
Send, XXX: New service as Notified by Email
return

^9:: ; Search for service by user/service

search := UserName()

if NOT isFireFoxActive()
{
Run, %FireFoxpath%
sleep 500
}
Send, ^t
Send, https://example.com/service/?q=%search%{Enter}
return

UserName()
{
return ExtractInfo(1)
}

ServerName()
{
return ExtractInfo(2)
}


isEmailAddress(emailstr){
static regex
regex := "is)^(?:""(?:\\\\.|[^""])*""|[^@]+)@(?=[^()]*(?:\([^)]*\)"
. "[^()]*)*\z)(?![^ ]* (?=[^)]+(?:\(|\z)))(?:(?:[a-z\d() ]+(?:[a-z\d() -]*[()a-"
. "z\d])?\.)+[a-z\d]{2,6}|\[(?:(?:1?\d\d?|2[0-4]\d|25[0-4])\.){3}(?:1?\d\d?|"
. "2[0-4]\d|25[0-4])\]) *\z"
return RegExMatch(emailstr, regex) != 0
}

ServiceID()
{
sid := ExtractInfo(1)
If RegexMatch(sid, "[^0-9]")
sid := ""
return sid
}

GetServiceIDs()
{
sids := Array()
SavedClipboard := ClipboardAll
Clipboard := ""
Send, ^c
ClipWait, 1
SelectedText := Clipboard
Clipboard := SavedClipboard
Loop, parse, SelectedText, `n, `r
{
arr := StrSplit(Trim(A_LoopField), A_Tab)
col1 := arr[1]
col2 := arr[2]
If col1 is digit
sids.push(col1)
else if col2 is digit
sids.push(col2)
}
return sids
}

ExtractInfo(pos)
{
SavedClipboard := ClipboardAll
Clipboard := ""
Send, ^c
ClipWait, 1
SelectedText := TidyInfo(Clipboard)
Clipboard := SavedClipboard
extract_arr := StrSplit(SelectedText,[".","@","-",A_Space,A_Tab])
extract := extract_arr[pos]
If RegexMatch(extract, "[^0-9a-zA-Z]")
extract := ""
return extract
}

ExtractEmail()
{
SavedClipboard := ClipboardAll
Clipboard := ""
Send, ^c
ClipWait, 1
SelectedText := TidyInfo(Clipboard)
Clipboard := SavedClipboard
if isEmailAddress(SelectedText)
return SelectedText
else
return ""
}

TidyInfo(strTidy)
{
if InStr(strTidy,".abc.com")
strTidy := SubStr(strTidy,1,InStr(strTidy,".abc.com")-1)
; while InStr(strTidy,"-")
; strTidy := SubStr(strTidy, InStr(strTidy,"-")+1)
strTidy := Trim(strTidy)
return strTidy
}

ChromeActive()
{
return IsActive("Chrome.exe")
}

isFireFoxActive()
{
return IsActive("FireFox.exe")
}

IsActive(path)
{
WinGet, active, ProcessPath, A
return InStr(active, path)
}
html_decode(html) {
; original name: ComUnHTML() by 'Guest' from
; html := RegExReplace(html, "\r?\n|\r", "<br>") ; added this because original strips line breaks
oHTML := ComObjCreate("HtmlFile")
oHTML.write(html)
return % oHTML.documentElement.innerText
}

jos...@main.nc.us

unread,
May 15, 2023, 7:02:50 PM5/15/23
to autoke...@googlegroups.com
Welcome to the AutoKey community Varg.

That's quite an involved script that apparently does many things and uses
external utilities to do some of them.

IDK AHK, but a few of our users do. I would recommend asking on Gitter
where our advanced users hang out.

https://gitter.im/autokey/autokey

If someone is interested, you can take the discussion to a private channel
to see if an arrangement can be made. (We're also on Discord, so that
could potentially be used for a private chat or you could use whatever
else works.)

If you don't get any takers, then you could rewrite the script in
something closer to English such as pseudocode which specifies what it
needs to do (without all the details of how to do it) so people (like me)
who don't know AHK can help.

If the whole thing can be broken down into smaller tasks, then you might
have more luck getting them implemented piece by piece rather than having
to address the whole daunting thing in one go.

I don't like to send people to other projects, but Espanso claims to have
a utility which converts AHK scripts into their native scripts and there
are a couple of ports of AHK to Linux that are in varied states of
development.
You can find some links on our GitHub site

https://github.com/autokey/autokey/discussions/775

Joe
> --
> You received this message because you are subscribed to the Google Groups
> "autokey-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to autokey-user...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/autokey-users/24e26270-1afb-48cf-9a8a-ec5b7f1af084n%40googlegroups.com.
>

Elliria

unread,
May 15, 2023, 11:22:16 PM5/15/23
to autoke...@googlegroups.com
Hey there,

I'm just going to jump in and say, "Oof. That's a lot of unfamiliar
code." It might be easier if you describe what you'd like it to do
rather than showing us some other program's code. There's very little
that AutoKey can't do, because it has full access to Python,
so if it can be coded, it can happen, and we'd be willing to help.

--
Elliria

There is no spoon.

varg

unread,
May 16, 2023, 4:38:06 AM5/16/23
to autokey-users
Yeah sorry. Basically, what I want Autokey to do is this:

On keybind, open a webbrowser (preferably Brave, or Firefox), go to a site, paste clipboard content into a field/form, submit form and then copy several fields/forms into variables that can be used when pressing another keybind. So second keybind could be pretty much the same thing, open a webpage and paste content into a field/form. Or open a terminal, use the variables (like username, password, servername, etc) and connect to an SSH server.

This is copied from what my colleague explained about the script:

So I created two functions: Username() Servername() They both just call another function ExtractInfo() Which basically: 1. Saves whatever is currently stored in the clipboard (i.e. before you click CTRL-0) 2. Copies into the clipboard whatever is currently highlighted (so it just does a CTRL-C) 3. Saves to a variable and tidies it up (gets rid of leading, trailing spaces, etc) via TidyInfo function I created (can be improved) 4. Restores clipboard back to original state 5. Splits the string from the clipboard into Username or Servername depending on whether (1) or (2) sent to ExtractInfo 6. Returns extracted Username or Servername



jos...@main.nc.us

unread,
May 16, 2023, 3:25:25 PM5/16/23
to autoke...@googlegroups.com
That sounds a lot simpler. There are still a bunch of steps, but almost
all of them appear to be relatively easy.

If you code and test these steps one at a time, the whole thing should be
quite doable.

Aside from actual coding, there seem to be passwords being saved in the
clear. This should be minimized as much possible because it's a major
security hole. AutoKey doesn't have any encryption tools built into it,
but you could access them with Python if necessary.

If you are only using passwords for ssh, then consider using ssh keys
instead. They are a bit annoying to setup the first time, but once you
have them, they are much easier to use and don't expose any secrets when
they are used.

Forms can be tricky. The simple way of dealing with them is to tab from
field to field doing whatever is needed at each field. This only works if
the fields are fixed in number and sequence and are all accessible in the
tabbing sequence. If they don't meet all these criteria, it can still be
done, but it involves more code to "visually" search for some of the
fields.

If such scripts are coded simplistically, then if anything goes wrong and
the cursor ends up somewhere unexpected, the script keeps going anyway and
can cause rather spectacular failures.

One of my scripts that deals with print dialogs has been known to
completely screw up my screen while I wait powerlessly for it to cease and
desist - when I accidentally trigger it in the wrong window (and for the
AutoKey coders here, no, window filters don't prevent this from
occurring).

If one script has to set things up for the next script (E.g. One script
gets the input data for the next script(s) to use to put that data to use,
then the data can be stored in AutoKey global variables in one script and
retrieved from them in the next script(s).

Joe
> --
> You received this message because you are subscribed to the Google Groups
> "autokey-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to autokey-user...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/autokey-users/84798263-2fe5-438e-a702-a8539ddae46bn%40googlegroups.com.
>

varg

unread,
May 16, 2023, 6:10:11 PM5/16/23
to autokey-users
>If you code and test these steps one at a time, the whole thing should be
quite doable.

That's the problem, I don't code. I can look at bash, python and get an understanding of what the script does. I can copypaste sections and with trial and error get stuff to work. But i'm not a coder by any means. Hence why i'm here asking for help. I've managed to get this working:

```
import webbrowser
import time

time.sleep(0.1)
site = "https://google.com"
webbrowser.get('brave %s').open_new(site)
```

>Aside from actual coding, there seem to be passwords being saved in the
clear. This should be minimized as much possible because it's a major
security hole. 

I'm fully aware of this, but they won't be long-term stored in a file. They'll pretty much be stored temporary in clipboard, or however the AutoHotKey script is set up.


>If you are only using passwords for ssh, then consider using ssh keys
instead.

I am personally using SSH keys. But this unfortunately won't be an option in this scenario.

If it's not too much to ask, would you mind giving me simplistic script examples of each of these steps I've mentioned? Having those as templates would help a lot. 
Message has been deleted

Little Girl

unread,
May 18, 2023, 5:44:41 PM5/18/23
to autokey-users
First, I'm going to comment on your current code:
* There's no need to import time because AutoKey does that for you already.
* You don't need the delay that you put into the beginning of your code unless you're having an issue that requires it.
* Variables and function names should use all lower-case letters with words separated by underscores. See: https://peps.python.org/pep-0008/#function-and-variable-names

Second, I wanted to comment on the passwords. In my opinion, it's never a good idea to store passwords on the clipboard. This is because many operating systems offer a clipboard manager by default and those tend to store a history of your clippings, which means that the password would be stored in plain text for an unknown period of time and could be read by anybody.

Third, I came up with some templates for you, but not all. More information will be needed for a couple of them (you'll see comments for those in the code). Google will mess the code up horribly, so I'm pasting it to the pasting site used by the Python IRC group and linking to it here, and it will be available for 30 days from today: https://bpa.st/3X3DG

Note that I made a "Debug" section at the bottom of it that shows you what's on the clipboard, in the selection, and in the tidied input after the whole thing runs. You don't have to keep those, but you can do what you like with the three variables.

varg

unread,
May 19, 2023, 5:38:10 AM5/19/23
to autokey-users
Thank you for taking the time and creating the template. This gives me a lot more building blocks that I can use to hopefully some day fully translate this script. It'll definitely keep me busy for a while, until I hit the next wall lol.

Johnny Rosenberg

unread,
May 19, 2023, 5:52:14 PM5/19/23
to autoke...@googlegroups.com
Den tors 18 maj 2023 kl 23:42 skrev Little Girl <littl...@gmail.com>:
First, I'm going to comment on your current code:
* There's no need to import time because AutoKey does that for you already.
* You don't need the delay that you put into the beginning of your code unless you're having an issue that requires it.
* Variables and function names should use all lower-case letters with words separated by underscores. See: https://peps.python.org/pep-0008/#function-and-variable-names

I always wondered WHY, so I clicked that link. I still didn't find out why, but I found this sentence:
”mixedCase is allowed only in contexts where that’s already the prevailing style (e.g. threading.py), to retain backwards compatibility.”

I prefer MixedCase (not mixedCase) because it seems like nobody else does it. That way I can easily see which variables are mine and which ones comes from built-in stuff or libraries that I might use. Why is this a bad thing again?


Kind regards

Johnny Rosenberg
 


Second, I wanted to comment on the passwords. In my opinion, it's never a good idea to store passwords on the clipboard. This is because many operating systems offer a clipboard manager by default and those tend to store a history of your clippings, which means that the password would be stored in plain text for an unknown period of time and could be read by anybody.

Third, I came up with some templates for you, but not all. More information will be needed for a couple of them (you'll see comments for those in the code). Google will mess the code up horribly, so I'm pasting it to the pasting site used by the Python IRC group and linking to it here: https://bpa.st/3X3DG


Note that I made a Debug section at the bottom of it that shows you what's on the clipboard, in the selection, and in the tidied input after the whole thing runs. You don't have to keep those, but you can do what you like with the three variables.

Little Girl

unread,
May 19, 2023, 7:46:08 PM5/19/23
to autokey-users
Hey there,

My pleasure. Depending on how much else you'd like to do (because I noticed you have some browser-related tasks to accomplish as well), you're nearly there. Also, if you provide the needed information for the two incomplete items from your list, those can be done, too.

Little Girl

unread,
May 19, 2023, 8:03:39 PM5/19/23
to autokey-users
Hey there,

> Little Girl wrote:
Johnny Rosenberg wrote:
 
* Variables and function names should use all lower-case letters with words separated by underscores. See: https://peps.python.org/pep-0008/#function-and-variable-names

I always wondered WHY, so I clicked that link. I still didn't find out why, but I found this sentence:
”mixedCase is allowed only in contexts where that’s already the prevailing style (e.g. threading.py), to retain backwards compatibility.”

I prefer MixedCase (not mixedCase) because it seems like nobody else does it. That way I can easily see which variables are mine and which ones comes from built-in stuff or libraries that I might use. Why is this a bad thing again?

Ah. PEP 8 refers to your version of MixedCase as CapitalizedWords or CapWords or CamelCase. Those are used for class names and type variables, 

I think the reason for it is so that you can tell either instantly or pretty quickly which kind of object you're looking at from the naming convention it uses. It may also be a matter of comfort for folks to see something familiar instead of always having to adjust to different conventions. It would be nice if they'd add a reason or reasons to that PEP so that we'd not be just stuck guessing.

You've got a good reason for using CamelCase, but it's an upstream swim, which can sometimes be a rather lonely path. You're not alone, though. I've always liked UPPERCASE letters for all of my HTML tags, which goes against most conventions. It makes it so I can easily distinguish my tags from my content. Then, if I want to share my HTML code, I do some quick searching and replacing.

Reply all
Reply to author
Forward
0 new messages