Skip to content
AutoHotkey from Python: one process, no wrappers, bidirectional, all features.
Python AutoHotkey
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib/AutoHotkey
.hgignore
LICENSE
NOTICE
README.md
autohotkey.py
example.ahk
example.py
requirements.txt

README.md

Python ↔ AutoHotkey

Python with all the deliciousness of AutoHotkey's friendly Windows API interface.

Those familiar with AutoHotkey know how easily it makes window, mouse, and keyboard manipulation. But actually coding is only as good as you would expect from a scripting language.

Meanwhile Python is powerful and expressive, but making calls to the Windows API is agonizing. (It's not much better in C#.)

What if you could code in Python, but interact live and immediately with all of AutoHotkey? Keep your AutoHotkey code separate, unmuddled, minimalistic and have everything just work - even your hotkeys?

Example

import time
from datetime import datetime
from autohotkey import Script


ahk = Script("""
Send(text) {
    Send, % text
}

Init() {
    SetTitleMatchMode, 2
    MsgBox, Initialized.
}

#IfWinActive, Notepad
CapsLock::hotkey = insert time
""")


def poll():
    hotkey = ahk.get('hotkey')
    if not hotkey:
        return
    ahk.set('hotkey', '')
    if hotkey == "insert time":
        ahk.call('Send', datetime.now().strftime('%#I:%M %p'))


if __name__ == '__main__':
    while True:
        poll()
        time.sleep(0.01)

Description

This module launches an AutoHotkey.exe process, passing it a script via stdin. That script then listens for windows messages from Python, and responds via a stdout pipe.

Requirements

pywin32, which you can install via pip install pywin32 as of September 2019.

Usage

set(var, val), get(var), call(proc, ...), f(func, ...)

Built-in functions are directly callable, e.g. inNotepad = f('WinActive', "Notepad"). Commands must be in a user function. (So there's some AutoHotkey wrapping... of itself.) Init(), when present, is called during initialization.

To use an .ahk file

Script.from_file(path), and put test code in the auto-execution section. Python will only call Init(). This is a great way to prototype a GUI, and you can replace occurrences of {{text}} like Script.from_file(path, {'text': "Hello world"}).

example.py

if __name__ == '__main__':
    ahk = Script.from_file(r'example.ahk')
    ahk.call('MsgBox', "Hello World!")

example.ahk

MsgBox("This is only displayed when running the script directly.")

MsgBox(text) {
    MsgBox, % text
}

To execute on main thread

Not everything plays nice when executed in the context of a fresh AutoHotkey OnMessage thread. call('DllCall', ...) causes Error 0x8001010d An outgoing call cannot be made since the application is dispatching an input-synchronous call. This is easily fixed by using call_main() instead. (Perhaps this should be default behavior.)

To use with PyInstaller

Tested and working; AutoHotkey bundled at lib\AutoHotkey\AutoHotkey.exe.

Concerns

Messages are easily spoofed to execute code arbitrarily, but this may be a moot point if it requires an already running process. There may be better methods of inter-process communication: sockets, memory-mapped files, and so on. This worked much better than I expected, but I am by no means an expert.

Thank you

To the AutoHotkey developers, and all those who have worked on bringing AHK to Python over the years. Special thanks to Ed Blake for PYAHK who surely struggled with AutoHotkey.dll as much as myself. (I changed course after working around too many continuable exception_access_violations and heap corruptions.)

You can’t perform that action at this time.