0
votes

I want to make hotstrings in python that converts one word when typed into another after some processing, since AHK is very limiting when it comes to determining which word to type. Right now, I am using a hotstring in ahk that runs code on the command line that runs a python script with the word that I typed as arguments. Then I use pyautogui to type the word. However, this is very slow and does not work when typing at speed. I'm looking for a way to do this all with python and without ahk, but I have not found a way to do hotstrings in python. For example, every time I type the word "test" it replaces it with "testing." Thanks for your help. I'm running the latest version of Python and Windows 10 if that is useful to anyone by the way.

1
"since AHK is very limiting when it comes to determining which word to type" I'd assume you just don't know how to do it. I doubt you could think of hotstring replacement that's possible in Python, but not in AHK. Could you maybe share your AHK code of what you tried to do? - 0x464e
In order to choose which word to type it will use a machine learning algorithm and choices from very complex matrices that are not possible to do in AHK. - Jack N
Ok, well that's new. I guess I can't comment on how possible it would be to do that since I don't know what this machine learning algorithm is. Maybe an option worth noting would be communicating between your AHK script and whatever you have that'll take care of the machine learning algorithm. The documentation for OnMessage() shows a simple way of receiving a custom message. - 0x464e
Thanks for your help. I'll take a look at that. Ideally though, it would all be done in Python though, since python is much better for the NLP and then there would be less of a delay. - Jack N

1 Answers

1
votes

(if you want to process it as each letter is typed(t,te,tes,test), you should edit your question)

I call my SymPy functions using ahk hotkeys. I register the python script as a COM server and load it using ahk.
I do not notice any latency.

you'll need pywin32, but don't download using pip install pywin32
download from https://github.com/mhammond/pywin32/releases
OR ELSE IT WON'T WORK for AutoHotkeyU64.exe, it will only work for AutoHotkeyU32.exe.
make sure to download amd64, (I downloaded pywin32-300.win-amd64-py3.8.exe)
here's why: how to register a 64bit python COM server

toUppercase COM server.py

class BasicServer:
    # list of all method names exposed to COM
    _public_methods_ = ["toUppercase"]

    @staticmethod
    def toUppercase(string):
        return string.upper()
        
if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("Error: need to supply arg (""--register"" or ""--unregister"")")
        sys.exit(1)
    else:
        import win32com.server.register
        import win32com.server.exception

        # this server's CLSID
        # NEVER copy the following ID 
        # Use "print(pythoncom.CreateGuid())" to make a new one.
        myClsid="{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}"
        # this server's (user-friendly) program ID
        myProgID="Python.stringUppercaser"
        
        if sys.argv[1] == "--register":
            import admin
            if not admin.isUserAdmin():
                admin.runAsAdmin()
            import pythoncom
            import os.path
            realPath = os.path.realpath(__file__)
            dirName = os.path.dirname(realPath)
            nameOfThisFile = os.path.basename(realPath)
            nameNoExt = os.path.splitext(nameOfThisFile)[0]
            # stuff will be written here
            # HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\${myClsid}
            # HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}
            # and here
            # HKEY_LOCAL_MACHINE\SOFTWARE\Classes\${myProgID}
            # HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.stringUppercaser
            win32com.server.register.RegisterServer(
                clsid=myClsid,
                # I guess this is {fileNameNoExt}.{className}
                pythonInstString=nameNoExt + ".BasicServer", #toUppercase COM server.BasicServer
                progID=myProgID,
                # optional description
                desc="return uppercased string",
                #we only want the registry key LocalServer32
                #we DO NOT WANT InProcServer32: pythoncom39.dll, NO NO NO
                clsctx=pythoncom.CLSCTX_LOCAL_SERVER,
                #this is needed if this file isn't in PYTHONPATH: it tells regedit which directory this file is located
                #this will write HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}\PythonCOMPath : dirName
                addnPath=dirName,
            )
            print("Registered COM server.")
            # don't use UseCommandLine(), as it will write InProcServer32: pythoncom39.dll
            # win32com.server.register.UseCommandLine(BasicServer)
        elif sys.argv[1] == "--unregister":
            import admin

            print("Starting to unregister...")

            if not admin.isUserAdmin():
                admin.runAsAdmin()
            win32com.server.register.UnregisterServer(myClsid, myProgID)

            print("Unregistered COM server.")
        else:
            print("Error: arg not recognized")

you first need to register the python COM server:
first, get your own CLSID: just use a python shell.

import pythoncom
print(pythoncom.CreateGuid())

then, set myClsid to that output

to register:
python "toUppercase COM server.py" --register
to unregister:
python "toUppercase COM server.py" --unregister

hotstring python toUppercase.ahk

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, force
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetBatchLines, -1
#KeyHistory 0
ListLines Off
#Persistent
#MaxThreadsPerHotkey 4

pythonComServer:=ComObjCreate("Python.stringUppercaser")
; OR
; pythonComServer:=ComObjCreate("{C70F3BF7-2947-4F87-B31E-9F5B8B13D24F}") ;use your own CLSID


; * do not wait for string to end
; C case sensitive
:*:hello world::

savedHotstring:=A_ThisHotkey

;theActualHotstring=savedHotstring[second colon:end of string]
theActualHotstring:=SubStr(savedHotstring, InStr(savedHotstring, ":",, 2) + 1)
send, % pythonComServer.toUppercase(theActualHotstring)


return



f3::Exitapp

you can test the speed of hotstring hello world, it's very fast for me.
Edit def toUppercase(string): to your liking