AutoHotkey v2.0.26 Linux port — a free, open-source macro-creation and automation utility for Linux. It is driven by a custom scripting language with special provision for defining keyboard shortcuts, otherwise known as hotkeys.
Status: technology preview (not "official release"). The v2 language coverage is broad (367 built-ins, 1134 doc-check assertions) and the X11/XWayland backend is usable for real automation; native-Wayland global hotkeys (GNOME Shell extension / Portal / evdev lanes), Unicode input on compositors without a virtual keyboard, AT-SPI control automation and IME state detection are implemented and machine-verified, while full cross-app automation depth and large-scale community validation are still young. See docs-v2/docs/linux-port.htm for the honest capability/limitation matrix before relying on it in production.
- Language: AutoHotkey v2 only. This port implements the v2 language. The v1 language, v1 commands and v1-to-v2 migration material are not part of this project.
- Upstream: https://www.autohotkey.com/ (the original Windows project;
this repository is a fork of the v2.0.26 release with a Linux port of the
interpreter on the
linux-portbranch). - Latest build:
v2.0.26-linux.15(see Releases). Doc-check 1134/1134 (regular + ASan), regression 27/27, Wayland 17/17, XWayland 247/247.
- Full X11 backend (preferred when
DISPLAYis set, including XWayland sessions): window management (Win*), controls (Control*), hotkeys (XGrabKey— keyboard + mouse buttons,~/Off/HotIf pass-through, BadAccess conflict reporting, left/right modifiers, wildcard), hotstring expansion (typed-text capture engine, all core options), InputHook live key capture, pixel/monitor access (PixelGetColor,PixelSearch,Monitor*,ImageSearch), dialogs (MsgBox,InputBox,FileSelect/DirSelect),ToolTip, window shapes (WinSetRegion), GTK3Gui/Menuand the whole doc-checked v2 API surface — 1134/1134 assertions pass under Xvfb. - Unicode text input (linux.13/linux.14):
SendText/Sendand hotstring replacements deliver non-ASCII characters (Chinese, Japanese, Korean, accented Latin, Emoji) on X11/XWayland via keysym transmission (a spare keycode is temporarily remapped when the layout has no binding, like xdotool; linux.14 serializes the borrow through an X selection lease so concurrent AHK processes never clash, with a dual-process doc-check regression (two independent processes send different CJK characters to the same X server simultaneously); on pure Wayland non-ASCII runs use the controlled clipboard-paste fallback (which waits for the target to consume the offer, restores an empty original to empty, and can be disabled withAHK_WAYLAND_PASTE=0) whenever a key-injection lane exists — the virtual-keyboard protocol (wlroots/sway) or the uinput virtual keyboard (/dev/uinput, GNOME/KWin;AHK_UINPUT=0disables); where no lane exists a clear error names the character instead of silently dropping it. - Native Wayland backend (used when no X display is available):
xdg-shell windows, virtual keyboard/pointer input
(
zwp_virtual_keyboard_v1/zwlr_virtual_pointer_manager_v1), screen capture viawlr-screencopy— 17 Wayland + 247 XWayland assertions pass under sway. - Unified input backend (linux.12+):
AHK_INPUT_BACKEND=auto|x11| portal|gnome-shell|evdevselects the global-hotkey backend — X11XGrabKey/XGrabButtonon X sessions; the GNOME Shell extension (GNOME 49 Wayland, zero-confirmation exclusive hotkeys:1::/^1::/F12::grab the physical key with no per-binding dialog, with automatic re-registration after extension disable/enable (VM verified) and fail-open release on exit; linux.15 fixesHotkey()never reaching the Wayland backends on Wayland sessions (the X-only guard is gone), and the Activated signal sender check now matches the broker's unique bus name (D-Bus delivers unique names, not well-known ones) — the extension backend is end-to-end usable; the standard XDG Global Shortcuts Portal backend remains the KDE/other-Wayland fallback (deny/cancel: no crash, no fire, clean exit — regression suite).AHK_FORCE_GLOBAL_SHORTCUTS=1keeps its documented meaning (explicitly require the Portal backend; only1/true/yes/oncount as true, and an unknownAHK_INPUT_BACKENDvalue prints a clear startup warning). - Hotstring (round-32): real expansion of
Hotstring()from the typed stream — the all-keys capture engine holds trigger prefixes and, on a full match (end char or*), suppresses the trigger and sends the replacement (or runs theX-option callback). OptionsC/*/O/X, case conforming,HotIfcriteria; verified against the independentxkeycapclient. Round-34: Unicode trigger words (CJK, accented text) are matched character-for-character through the Unicode keysym stream. - InputHook (round-33/34): live key capture while a hook is
InProgress— buffer fill, single-char/named end keys (EndChar/EndKey), match list, backspace undo, input suppression;OnChar/OnKeyDown/OnKeyUpnotifications (round-34) are queued by the capture engine and fired from the main-loop dispatch (Windows semantics: VK/SC for keys, the character for OnChar, Unicode included). - System clipboard:
A_Clipboardintegrates with the desktop clipboard (X11 CLIPBOARD selection on X11/XWayland, wl_data_device on Wayland; process-internal fallback headless), verified cross-process with xclip. The bounded read/wait window is configurable:AHK_CLIPBOARD_TIMEOUT_MS(default 2000) covers slow clipboard owners (a slow app that only serves the request late); the slow-owner regression is part of the doc-check suite. - AT-SPI control automation (Wayland):
ControlGetText,ControlSetTextandControlClickin a Wayland session (GNOME 49 verified) resolve the control as an AT-SPI accessible name over the org.a11y.atspi bus (read text /EditableText.SetTextContents/Action.DoAction("click")), so GTK/Qt/Electron apps with accessibility enabled can be driven without an X display. Verified end-to-end on a GTK3 app (read label → click button → label changed). - IME active-state detection:
ImeGetState()returns the active input-method framework (ibus / fcitx5 by session-bus owner) and the current XKB group (the effective layout/IME group on X11). Preedit reading, IME toggling and wlroots input-method-v2 text delivery are documented as out of scope (mutter does not implement the zwlr protocol — see docs/IME-Integration.md for the honest record). - DllCall for native libraries: calls functions in Linux shared
objects (
.so) via dlopen/dlsym + libffi — full type support (Int/Int64/Short/Char/Float/Double/Ptr/Str/AStr/WStr), by-address&Varoutput parameters and HRESULT-style error reporting (29 doc-check assertions). - COM over D-Bus:
ComObject("service")proxies a D-Bus bus service; method calls and property access map to D-Bus;ComValuewraps typed values (18 doc-check assertions). Windows COM interfaces do not exist on Linux. - 367/370 built-in functions implemented (3 are intentionally
not-implemented with a clear error:
ComObjArray,TraySetIconandTrayTip); seetests/doccheck/CHECK_REPORT.mdfor the per-module report andtests/doccheck/worklist.tsvfor the per-function status. - CI: GitHub Actions builds both the regular and ASan binaries and runs the full suite (headless, Xvfb, Wayland, XWayland) on every push; dependency install is hardened against runner apt-mirror stalls (IPv4/timeouts/retries + azure.archive.ubuntu.com fallback).
Prebuilt packages are attached to each GitHub Release:
# Debian/Ubuntu (system-wide; extension ships in the deb, dpkg-managed)
sudo apt install ./autohotkey-linux-<version>-amd64.deb
# ... after install: gnome-extensions enable [email protected]
# (one line, once per user; then restart GNOME Shell / Alt+F2 'r')
# Fedora / openSUSE (RPM; system-wide, extension bundled, dnf-managed)
sudo dnf install ./autohotkey-linux-<version>-amd64.rpm
# Arch (PKGBUILD; system-wide, extension bundled, pacman-managed)
# (build from tools/linux/PKGBUILD into your package repo / AUR)
# Generic tarball (run the GUI or CLI installer from the unpacked tree)
tar xzf autohotkey-linux-<version>-amd64.tar.gz
cd autohotkey-linux
./tools/linux/install-gui.sh # graphical wizard (zenity/yad)
# or
./tools/linux/install.sh --prefix ~/.local --gnome-extension
# AppImage (portable single file; extension copied user-side on demand)
./autohotkey-linux-<version>-amd64.AppImage --install-extensionThe installer places the ahk launcher, the interpreter and the
documentation under the chosen prefix:
ahk --version # AutoHotkey v2.0.26 Linux port v2.0.26-linux.15
ahk --check # integrity, install method, latest release check
ahk your-script.ahk
ahk --uninstall # cleanly remove this installation
ahk --update # update to the latest GitHub release
ahk --update 2.0.26-linux.15 # or a specific release (upgrade or downgrade)Note: launcher commands are
--prefixed (--update,--uninstall,--check,--version) so plain names such asahk update.ahkare always treated as scripts. Every release since v2.0.26-linux.15 stays published on the GitHub Releases page (with aCKSUMS.txtof SHA-256 hashes), so the tarball'sahk --update <VER>can upgrade or downgrade to any published release; fixes and bespoke state can therefore be rolled back to an older known release. Releases before linux.15 were removed when the new installer line shipped; their source remains available on thev2.0.26-linux.*git tags for source-level rollback.
What
ahk --update/ahk --uninstalldo by install method. The launcher detects how the copy was installed and routes the command accordingly:
- tarball / user prefix:
ahk --update [VER]downloads the release tarball and reinstalls over the same prefix (upgrade or downgrade);ahk --uninstallremoves the prefix files. The GNOME extension is never touched by either..deb(Debian/Ubuntu):--update/--uninstallprint theapt/dpkgequivalent (sudo apt install --only-upgrade autohotkey-linux/sudo apt remove autohotkey-linux) — package state stays consistent. The extension is dpkg-managed: package upgrade updates it,apt removedeletes it.- RPM (Fedora/openSUSE):
--update/--uninstallprint thednf/rpmequivalent (sudo dnf update autohotkey-linux/sudo dnf remove autohotkey-linux). The extension ships with the package and is removed with it.- Arch (pacman):
--update/--uninstallprintsudo pacman -Syu/sudo pacman -Rns autohotkey-linux. The extension ships with the package and is removed with it.- AppImage:
--install-extensioncopies the bundled extension to the user's GNOME extensions dir and enables it;--updatedownloads the newest AppImage next to the running file. (The launcher-package commands apply to the deb/RPM/pacman/tarball installs; the AppImage handles these two passthrough commands itself and runs scripts otherwise.) See the release notes for the checksums.
First install on GNOME Wayland? Run the installer once with
--gnome-extension(e.g../tools/linux/install.sh --prefix ~/.local --gnome-extension), or answer "y" when the interactive installer asks, to also copy and enable the optional global-hotkeys GNOME Shell extension in one step. You must then restart GNOME Shell (log out/in, or press Alt+F2 and typer) — a freshly-placed extension only loads at the next Shell start, andgnome-extensions enablealone registers the choice without hot-loading a brand-new extension. After the restartahk --checkshows its state. Later core updates never touch the extension; the.deb/tarball itself still never activates it by default (no GNOME session = nothing happens).
What (un)install/update do and do not touch. The installer (
install.sh),ahk --uninstallandahk --updateonly manage the files under the chosen install prefix (theahklauncher, the interpreterahk_core, the include files and the bundled documentation). They do not install, activate, deactivate, overwrite or delete the GNOME Shell extension ([email protected]) — that is a separate, user-scoped component living in~/.local/share/gnome-shell/extensions/(or/usr/share/gnome-shell/ extensions/), enabled on the GNOME Shell side withgnome-extensions enable. In particularahk --updatenever touches the extension, so an installed/enabled extension survives every core update (the extension is itself version-loose with a stable D-Bus surface; seedocs-v2/docs/howto/Install.htm).ahk --uninstallalso leaves the extension in place — remove it separately withgnome-extensions disable ...and by deleting its directory. Theahk --checkcommand reports whether the extension is installed and enabled.
Do not confuse the layers when updating the core: (re)installing a newer interpreter, or rolling back to an older one, never registers, deregisters or re-registers the GNOME extension. If a future release ships a newer extension, install/update it as an extension update (replace the directory at the same location), not as part of the core package; the same guarantee applies in the reverse direction (rolling back the core never un-installs the extension).
Requirements: CMake, a C++ compiler, X11 development headers
(libx11-dev libxext-dev libxrandr-dev libxinerama-dev libxtst-dev libxi-dev),
Wayland development headers (libwayland-dev wayland-protocols),
libxkbcommon-dev, libffi-dev (DllCall), libdbus-1-dev (COM/D-Bus) and
libgtk-3-dev (GUI).
git clone --branch linux-port https://github.com/MonoEven/Autohotkey_Linux.git
cd Autohotkey_Linux
cmake -S . -B build-core
cmake --build build-core -j$(nproc)
build-core/source/linux/core/ahk_core your-script.ahkBuild a release package (tar.gz + .deb):
bash tools/linux/pack.shThe official AutoHotkey v2 documentation pages (adapted for this port) are published on GitHub Pages:
https://monoeven.github.io/Autohotkey_Linux/
The docs live in docs-v2/. The v1-to-v2 change documentation is omitted
because v1 is not supported by this port; see
docs-v2/docs/linux-port.htm for the Linux
port overview (backends, differences from Windows, build/install notes).
The docs site is English-only.
- GUI:
Gui/GuiControl/Menuare implemented over GTK3 and work on X11/XWayland (they need a display; pure headless sessions raise a clear error). - COM is implemented over D-Bus (no IUnknown/IDispatch/SafeArray
pointers, no COM events);
ComObjArrayraises an error. - No Windows registry, no Win32 messages to other windows
(
SendMessage/PostMessage/OnMessageare not available). DllCallloads native .so shared objects — Windows DLLs are not loadable.- Sound:
SoundBeep/SoundPlayare implemented (aplay/paplay);SoundGet*/SoundSet*needpactl/amixerinstalled. There is no tray icon, soTrayTip/TraySetIconraise a clear error. - Hotkeys, hotstrings and InputHook capture work through XGrabKey +
the typed-text capture engine on X11/XWayland; in Wayland sessions
global hotkeys go through the GNOME Shell extension or the Global
Shortcuts Portal (see the input-backend bullet above; bare
~-style passthrough and full remapping on Wayland are the evdev/ahk-inputd roadmap — seedocs-v2/docs/linux-port.htmfor the compatibility matrix and the evdev/inputd design notes).
- MonoEven — author and maintainer of the Linux port: source-level port of the interpreter, X11/Wayland/evdev input backends, the GNOME Shell extension, AT-SPI and IME integration, packaging/CI and the documentation in this repository.
This port is an independent implementation, but it builds on the ideas and feedback of the wider AutoHotkey-on-Linux community:
- AHK_X11 — a from-scratch reimplementation of AutoHotkey v1 (2004-era syntax) in Crystal, X11-only (XRecord global key monitoring + XTEST injection), with its own single-binary AppImage distribution. It is the most widely used AutoHotkey-on-Linux project before this one and a frequent reference point for X11 key capture and injection behavior (see also the AHK_X11 thread on the AutoHotkey forum).
- AutoHotkey v2 — the upstream Windows project this fork is based on; all language semantics come from it.
- The AutoHotkey Community forum — the primary support channel for the language.
- Issues: https://github.com/MonoEven/Autohotkey_Linux/issues
- The AutoHotkey Community forum is the primary upstream support channel for AutoHotkey v2.
GNU General Public License — see LICENSE.