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.
Type Name Latest commit message Commit time
Failed to load latest commit information.

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?


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:
    ahk.set('hotkey', '')
    if hotkey == "insert time":'Send','%#I:%M %p'))

if __name__ == '__main__':
    while True:


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.


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


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"}).

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


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.


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.