# ahk
A fully typed Python wrapper around AutoHotkey.
[![Docs](https://readthedocs.org/projects/ahk/badge/?version=latest)](https://ahk.readthedocs.io/en/latest/?badge=latest)
[![Build](https://github.com/spyoungtech/ahk/actions/workflows/test.yaml/badge.svg)](https://github.com/spyoungtech/ahk/actions/workflows/test.yaml)
[![version](https://img.shields.io/pypi/v/ahk.svg?colorB=blue)](https://pypi.org/project/ahk/)
[![pyversion](https://img.shields.io/pypi/pyversions/ahk.svg?)](https://pypi.org/project/ahk/)
[![Coverage](https://coveralls.io/repos/github/spyoungtech/ahk/badge.svg?branch=master)](https://coveralls.io/github/spyoungtech/ahk?branch=master)
[![Downloads](https://pepy.tech/badge/ahk)](https://pepy.tech/project/ahk)
# Installation
```
pip install ahk
```
Requires Python 3.8+
Supports AutoHotkey v1 and v2. See also: [Non-Python dependencies](#deps)
# Usage
```python
from ahk import AHK
ahk = AHK()
ahk.mouse_move(x=100, y=100, blocking=True) # Blocks until mouse finishes moving (the default)
ahk.mouse_move(x=150, y=150, speed=10, blocking=True) # Moves the mouse to x, y taking 'speed' seconds to move
print(ahk.mouse_position) # (150, 150)
```
![ahk](https://raw.githubusercontent.com/spyoungtech/ahk/9d049a327c7a10c9f19dfef89fc63668695023fc/docs/_static/ahk.gif)
# Examples
Non-exhaustive examples of some functions available with this package. See the [full documentation](https://ahk.readthedocs.io/en/latest/?badge=latest)
for complete API references and additional features.
## Hotkeys
Hotkeys can be configured to run python functions as callbacks.
For example:
```python
from ahk import AHK
def my_callback():
print('Hello callback!')
ahk = AHK()
# when WIN + n is pressed, fire `my_callback`
ahk.add_hotkey('#n', callback=my_callback)
ahk.start_hotkeys() # start the hotkey process thread
ahk.block_forever() # not strictly needed in all scripts -- stops the script from exiting; sleep forever
```
Now whenever you press <kbd>![Windows Key][winlogo]</kbd> + <kbd>n</kbd>, the `my_callback` callback function will be called in a background thread.
You can also add an exception handler for your callback:
```python
from ahk import AHK
ahk = AHK()
def go_boom():
raise Exception('boom!')
def my_ex_handler(hotkey: str, exception: Exception):
print('exception with callback for hotkey', hotkey, 'Here was the error:', exception)
ahk.add_hotkey('#n', callback=go_boom, ex_handler=my_ex_handler)
```
There are also methods for removing hotkeys:
```python
# ...
ahk.remove_hotkey('#n') # remove a hotkey by its keyname
ahk.clear_hotkeys() # remove all hotkeys
```
Note that:
- Hotkeys run in a separate process that must be started manually (with `ahk.start_hotkeys()`)
- Hotkeys can be stopped with `ahk.stop_hotkeys()` (will not stop actively running callbacks)
- Hotstrings (discussed below) share the same process with hotkeys and are started/stopped in the same manner
- If hotkeys or hotstrings are added or removed while the process is running, the underlying AHK process is restarted automatically
See also the [relevant AHK documentation](https://www.autohotkey.com/docs/Hotkeys.htm)
## Hotstrings
[Hotstrings](https://www.autohotkey.com/docs/Hotstrings.htm) can also be added to the hotkey process thread.
In addition to Hotstrings supporting normal AHK string replacements, you can also provide Python callbacks (with optional exception handlers) in response to hotstrings triggering.
```python
from ahk import AHK
ahk = AHK()
def my_callback():
print('hello callback!')
ahk.add_hotstring('btw', 'by the way') # string replacements
ahk.add_hotstring('btw', my_callback) # call python function in response to the hotstring
```
You can also remove hotstrings:
```python
ahk.remove_hotstring('btw') # remove a hotstring by its trigger sequence
ahk.clear_hotstrings() # remove all registered hotstrings
```
## Mouse
```python
from ahk import AHK
ahk = AHK()
ahk.mouse_position # Returns a tuple of mouse coordinates (x, y) (relative to active window)
ahk.get_mouse_position(coord_mode='Screen') # get coordinates relative to the screen
ahk.mouse_move(100, 100, speed=10, relative=True) # Moves the mouse reletave to the current position
ahk.mouse_position = (100, 100) # Moves the mouse instantly to absolute screen position
ahk.click() # Click the primary mouse button
ahk.click(200, 200) # Moves the mouse to a particular position and clicks (relative to active window)
ahk.click(100, 200, coord_mode='Screen') # click relative to the screen instead of active window
ahk.click(button='R', click_count=2) # Clicks the right mouse button twice
ahk.right_click() # Clicks the secondary mouse button
ahk.mouse_drag(100, 100, relative=True) # Holds down primary button and moves the mouse
```
## Keyboard
```python
from ahk import AHK
ahk = AHK()
ahk.type('hello, world!') # Send keys, as if typed (performs string escapes for you)
ahk.send_input('Hello, {U+1F30E}{!}') # Like AHK SendInput
# Unlike `type`, control sequences must be escaped manually.
# For example the characters `!^+#=` and braces (`{` `}`) must be escaped manually.
ahk.key_state('Control') # Return True or False based on whether Control key is pressed down
ahk.key_state('CapsLock', mode='T') # Check toggle state of a key (like for NumLock, CapsLock, etc)
ahk.key_press('a') # Press and release a key
ahk.key_down('Control') # Press down (but do not release) Control key
ahk.key_up('Control') # Release the key
ahk.set_capslock_state("On") # Turn CapsLock on
if ahk.key_wait('x', timeout=3): # wait for a key to be pressed; returns a boolean
print('X was pressed within 3 seconds')
else:
print('X was not pressed within 3 seconds')
```
## Windows
You can do stuff with windows, too.
### Getting windows
```python
from ahk import AHK
ahk = AHK()
win = ahk.active_window # Get the active window
win = ahk.win_get(title='Untitled - Notepad') # by title
all_windows = ahk.list_windows() # list of all windows
win = ahk.win_get_from_mouse_position() # the window under the mouse cursor
win = ahk.win_get(title='ahk_pid 20366') # get window from pid
# Wait for a window
try:
# wait up to 5 seconds for notepad
win = ahk.win_wait(title='Untitled - Notepad', timeout=5)
# see also: win_wait_active, win_wait_not_active
except TimeoutError:
print('Notepad was not found!')
```
### Working with windows
```python
from ahk import AHK
ahk = AHK()
ahk.run_script('Run Notepad') # Open notepad
win = ahk.find_window(title='Untitled - Notepad') # Find the opened window; returns a `Window` object
# Window object methods
win.send('hello', control='Edit1') # Send keys directly to the window (does not need focus!)
# OR ahk.control_send(title='Untitled - Notepad', control='Edit1')
win.move(x=200, y=300, width=500, height=800)
win.activate() # Give the window focus
win.close() # Close the window
win.hide() # Hide the window
win.kill() # Kill the window
win.maximize() # Maximize the window
win.minimize() # Minimize the window
win.restore() # Restore the window
win.show() # Show the window
win.disable() # Make the window non-interactable
win.enable() # Enable it again
win.to_top() # Move the window on top of other windows
win.to_bottom() # Move the window to the bottom of the other windows
win.get_class() # Get the class name of the window
win.get_minmax() # Get the min/max status
win.get_process_name() # Get the process name (e.g., "notepad.exe")
win.process_name # Property; same as `.get_process_name()` above
win.is_always_on_top() # Whether the window has the 'always on top' style applied
win.list_controls() # Get a list of controls (list of `Control` objects)
win.redraw() # Redraw the window
win.set_style("-0xC00000") # Set a style on the window (in this case, removing the title bar)
win.set_ex_style("^0x80") # Set an ExStyle on the window (in this case, removes the window from alt-tab list)
win.set_region("") # See: https://www.autohotkey.com/docs/v2/lib/WinSetRegion.htm
win.set_trans_color("White") # Makes all pixels of the chosen color invisible inside the specified window.
win.set_transparent(155) # Makes the specified window semi-transparent (or "Off" to turn off transparency)
win.always_on_top = 'On' # Make the window always on top
# or
win.set_always_on_top('On')
for window in ahk.list_windows(): # list all (non-hidden) windows -- ``detect_hidden_windows=True`` to include hidden
print(window.title)
# Some more attributes
print(window.text) # window text -- or .get_text()
print(window.get_position()) # (x, y, width, height)
print(window.id) # the ahk_id of the window
print(window.pid) # process ID -- or .get_pid()
print(window.process_path) # or .get_process_path()
if win.active: # or win.is_active()
...
if win.exist: # or win.exists()
...
# Controls
edit_control = win.list_controls()[0] # get the first control for the window, in this case "Edit1" for Notepad
edit_control.get_text() # get the text in Notepad
edit_control.get_position() # returns a `Postion` namedtuple: e.g. Position(x=6, y=49, width=2381, height=1013)
```
Various window methods can also be called directly without first creating a `Window` object by using the underlying `win_*` methods on the `AHK` class.
For example, instead of `win.close()` as above, one could call `ahk.win_close(title='Untitled - Notepad')` instead.
## Screen
```python
from ahk import AHK
ahk = AHK()
ahk.image_search('C:\\path\\to\\image.jpg') # Find an image on screen
# Find an image within a boundary on screen
ahk.image_search('C:\\path\\to\\image.jpg', upper_bound=(100, 100), # upper-left corner of search area
lower_bound=(400, 400)) # lower-right corner of search area
ahk.pixel_get_color(100, 100) # Get color of pixel located at coords (100, 100)
ahk.pixel_search(color='0x9d6346', search_region_start=(0, 0), search_region_end=(500, 500)) # Get coords of the first pixel with specified color
```
## Clipboard
Get/set `Clipboard` data
```python
from ahk import AHK
ahk = AHK()
ahk.set_clipboard('hello \N{EARTH GLOBE AMERICAS}') # set clipboard text contents
ahk.get_clipboard() # get clipboard text contents
# 'hello 🌎'
ahk.set_clipboard("") # Clear the clipboard
ahk.clip_wait(timeout=3) # Wait for clipboard contents to change (with text or file(s))
ahk.clip_wait(timeout=3, wait_for_any_data=True) # wait for _any_ clipboard contents
```
You may also get/set `ClipboardAll` -- however, you should never try to call `set_clipboard_all` with any other
data than as _exactly_ as returned by `get_clipboard_all` or unexpected problems may occur.
```python
from ahk import AHK
ahk = AHK()
# save all clipboard contents in all formats
saved_clipboard = ahk.get_clipboard_all()
ahk.set_clipboard('something else')
...
ahk.set_clipboard_all(saved_clipboard) # restore saved content from earlier
```
You can also set a callback to execute when the clipboard contents change. As with Hotkey methods mentioned above,
you can also set an exception handler. Like hotkeys, `on_clipboard_change` callbacks also require `.start_hotkeys()`
to be called to take effect.
The callback function must accept one positional argument, which is an integer indicating the clipboard datatype.
```python
from ahk import AHK
ahk = AHK()
def my_clipboard_callback(change_type: int):
if change_type == 0:
print('Clipboard is now empty')
elif change_type == 1:
print('Clipboard has text contents')
elif change_type == 2:
print('Clipboard has non-text contents')
ahk.on_clipboard_change(my_clipboard_callback)
ahk.start_hotkeys() # like with hotkeys, must be called at least once for listening to start
# ...
ahk.set_clipboard("hello") # will cause the message "Clipboard has text contents" to be printed by the callback
ahk.set_clipboard("") # Clears the clipboard, causing the message "Clipboard is now empty" to be printed by the callback
```
## Sound
```python
from ahk import AHK
ahk = AHK()
ahk.sound_play('C:\\path\\to\\sound.wav') # Play an audio file
ahk.sound_beep(frequency=440, duration=1000) # Play a beep for 1 second (duration in microseconds)
ahk.get_volume(device_number=1) # Get volume of a device
ahk.set_volume(50, device_number=1) # Set volume of a device
ahk.sound_get(device_number=1, component_type='MASTER', control_type='VOLUME') # Get sound device property
ahk.sound_set(50, device_number=1, component_type='MASTER', control_type='VOLUME') # Set sound device property
```
## GUI
Tooltips/traytips
```python
import time
from ahk import AHK
ahk = AHK()
ahk.show_tooltip("hello4", x=10, y=10)
time.sleep(2)
ahk.hide_tooltip() # hide the tooltip
ahk.show_info_traytip("Info", "It's also info", silent=False, blocking=True) # Default info traytip
ahk.show_warning_traytip("Warning", "It's a warning") # Warning traytip
ahk.show_error_traytip("Error", "It's an error") # Error trytip
```
Dialog boxes
```python
from ahk import AHK, MsgBoxButtons
ahk = AHK()
ahk.msg_box(text='Do you like message boxes?', title='My Title', buttons=MsgBoxButtons.YES_NO)
ahk.input_box(prompt='Password', title='Enter your password', hide=True)
ahk.file_select_box(title='Select one or more mp3 files', multi=True, filter='*.mp3', file_must_exist=True)
ahk.folder_select_box(prompt='Select a folder')
```
## Global state changes
You can change various global states such as `CoordMode`, `DetectHiddenWindows`, etc. so you don't have to pass
these parameters directly to function calls
```python
from ahk import AHK
ahk = AHK()
ahk.set_coord_mode('Mouse', 'Screen') # set default Mouse CoordMode to be relative to Screen
ahk.set_detect_hidden_windows(True) # Turn on detect hidden windows by default
ahk.set_send_level(5) # Change send https://www.autohotkey.com/docs/v1/lib/SendLevel.htm
ahk.set_title_match_mode('Slow') # change title match speed and/or mode
ahk.set_title_match_mode('RegEx')
ahk.set_title_match_mode(('RegEx', 'Slow')) # or both at the same time
ahk.set_send_mode('Event') # change the default SendMode
```
## Add directives
You can add directives that will be added to all generated scripts.
For example, to prevent the AHK trayicon from appearing, you can add the NoTrayIcon directive.
```python
from ahk import AHK
from ahk.directives import NoTrayIcon
ahk = AHK(directives=[NoTrayIcon])
```
By default, some directives are automatically added to ensure functionality and are merged with any user-provided directives.
Directives are not applied for the AHK process used for handling hotkeys and hotstrings (discussed below) by default. To apply a directive
to the hotkeys process using the keyword argument `apply_to_hotkeys_process=True`:
```python
from ahk import AHK
from ahk.directives import NoTrayIcon
directives = [
NoTrayIcon(apply_to_hotkeys_process=True)
]
ahk = AHK(directives=directives)
```
## Menu tray icon
As discussed above, you can hide the tray icon if you wish. Additionally, there are some methods available for
customizing the tray icon.
```python
from ahk import AHK
ahk = AHK()
# change the tray icon (in this case, using a builtin system icon)
ahk.menu_tray_icon('Shell32.dll', 174)
# revert it back to the original:
ahk.menu_tray_icon()
# change the tooltip that shows up when hovering the mouse over the tray icon
ahk.menu_tray_tooltip('My Program Name')
# Hide the tray icon
ahk.menu_tray_icon_hide()
# Show the tray icon that was previously hidden by ``NoTrayIcon`` or ``menu_tray_icon_hide``
ahk.menu_tray_icon_show()
```
## Registry methods
You can read/write/delete registry keys:
```python
from ahk import AHK
ahk = AHK()
ahk.reg_write('REG_SZ', r'HKEY_CURRENT_USER\SOFTWARE\my-software', value='test')
ahk.reg_write('REG_SZ', r'HKEY_CURRENT_USER\SOFTWARE\my-software', value_name='foo', value='bar')
ahk.reg_read(r'HKEY_CURRENT_USER\SOFTWARE\my-software') # 'test'
ahk.reg_delete(r'HKEY_CURRENT_USER\SOFTWARE\my-software')
```
If a key does not exist or some other problem occurs, an exception is raised.
## non-blocking modes
Most methods in this library supply a non-blocking interface, so your Python scripts can continue executing while
your AHK scripts run.
By default, all calls are _blocking_ -- each function will execute completely before the next function is ran.
However, sometimes you may want to run other code while AHK executes some code. When the `blocking` keyword
argument is supplied with `False`, function calls will return immediately while the AHK function is carried out
in the background.
As an example, you can move the mouse slowly and report its position as it moves:
```python
import time
from ahk import AHK
ahk = AHK()
ahk.mouse_position = (200, 200) # Moves the mouse instantly to the start position
start = time.time()
# move the mouse very slowly
ahk.mouse_move(x=100, y=100, speed=30, blocking=False)
# This code begins executing right away, even though the mouse is still moving
while True:
t = round(time.time() - start, 4)
position = ahk.mouse_position
print(t, position) # report mouse position while it moves
if position == (100, 100):
break
```
When you specify `blocking=False` you will always receive a special `FutureResult` object (or `AsyncFutureResult` object in the async API, discussed below)
which allows you to wait on the function to complete and retrieve return value through a `get_result` function. Even
when a function normally returns `None`, this can be useful to ensure AHK has finished executing the function.
nonblocking calls:
- Are isolated in a new AHK process that will terminate after the call is complete
- Always start immediately
- Do not inherit previous global state changes (e.g., from `set_coord_mode` calls or similar) -- this may change in a future version.
- will not block other calls from starting
- will always return a special `FutureResult` object (or `AsyncFutureResult` object in the async API, discussed below)
which allows you to wait on the function to complete and retrieve return value through the `result` function. Even
when a function normally returns `None`, this can be useful to ensure AHK has finished executing the function.
```python
from ahk import AHK
ahk = AHK()
future_result = ahk.mouse_move(100, 100, speed=40, blocking=False)
...
# wait on the mouse_move to finish
future_result.result(timeout=10) # timeout keyword is optional
```
## Async API (asyncio)
An async API is provided so functions can be called using `async`/`await`.
All the same methods from the synchronous API are available in the async API.
```python
from ahk import AsyncAHK
import asyncio
ahk = AsyncAHK()
async def main():
await ahk.mouse_move(100, 100)
x, y = await ahk.get_mouse_position()
print(x, y)
asyncio.run(main())
```
The async API is identical to that of the normal API, with a few notable differences:
- While properties (like `.mouse_position` or `.title` for windows) can be `await`ed,
additional methods (like `get_mouse_position()` and `get_title()`) have been added for a more intuitive API and
are recommended over the use of properties.
- Property _setters_ (e.g., `ahk.mouse_postion = (200, 200)`) are not allowed in the async API (a RunTimeError is raised).
Property setters remain available in the sync API.
- `AsyncFutureResult` objects (returned when specifying `blocking=False`) work the same as the `FutureResult` objects in the sync API, except the `timeout` keyword is not supported for the `result` method).
Note also that:
- by default, awaited tasks on a single `AsyncAHK` instance will not run concurrently. You must either
use `blocking=False`, as in the sync API, or use multiple instances of `AsyncAHK`.
- There is no difference in working with hotkeys (and their callbacks) in the async vs sync API.
## type-hints and mypy
This library is fully type-hinted, allowing you to leverage tools like `mypy` to help validate the type-correctness
of your code. IDEs that implement type-checking features are also able to leverage type hints to help ensure your
code is safe.
## Run arbitrary AutoHotkey scripts
You can also run arbitrary AutoHotkey code either as a `.ahk` script file or as a string containing AHK code.
```python
from ahk import AHK
ahk = AHK()
my_script = '''\
MouseMove, 100, 100
; etc...
'''
ahk.run_script(my_script)
```
```python
from ahk import AHK
ahk = AHK()
script_path = r'C:\Path\To\myscript.ahk'
ahk.run_script(script_path)
```
<a name="deps"></a>
# Non-Python dependencies
To use this package, you need the [AutoHotkey executable](https://www.autohotkey.com/download/) (e.g., `AutoHotkey.exe`).
It's expected to be on PATH by default OR in a default installation location (`C:\Program Files\AutoHotkey\AutoHotkey.exe` for v1 or `C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe` for v2)
AutoHotkey v1 and v2 are both fully supported, though some behavioral differences will occur depending on which version
you use. See notes below.
The recommended way to supply the AutoHotkey binary (for both v1 and v2) is to install the `binary` extra for this package. This will
provide the necessary executables and help ensure they are correctly placed on PATH.
```
pip install "ahk[binary]"
```
Alternatively, you may provide the path in code:
```python
from ahk import AHK
ahk = AHK(executable_path='C:\\path\\to\\AutoHotkey.exe')
```
You can also use the `AHK_PATH` environment variable to specify the executable location.
```console
set AHK_PATH=C:\Path\To\AutoHotkey.exe
python myscript.py
```
## Using AHK v2
By default, when no `executable_path` parameter (or `AHK_PATH` environment variable) is set, only AutoHotkey v1 binary names
are searched for on PATH or default install locations. This behavior may change in future versions to allow v2 to be used by default.
To use AutoHotkey version 2, you can do any of the following things:
1. provide the `executable_path` keyword argument with the location of the AutoHotkey v2 binary
2. set the `AHK_PATH` environment variable with the location of an AutoHotkey v2 binary
3. Provide the `version` keyword argument with the value `v2` which enables finding the executable using AutoHotkey v2 binary names and default install locations.
For example:
```python
from ahk import AHK
ahk = AHK(executable_path=r'C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe')
# OR
ahk = AHK(version='v2')
```
When you provide the `version` keyword argument (with either `"v1"` or `"v2"`) a check is performed to ensure the provided (or discovered) binary matches the requested version. When
the `version` keyword is omitted, the version is determined automatically from the provided (or discovered) executable binary.
### Differences when using AutoHotkey v1 vs AutoHotkey v2
The API of this project is originally designed against AutoHotkey v1 and function signatures are the same, even when using AutoHotkey v2.
While most of the behavior remains the same, some behavior does change when using AutoHotkey v2 compared to v1. This is mostly due to
[underlying differences](https://www.autohotkey.com/docs/v2/v2-changes.htm) between the two versions.
Some of the notable differences that you may experience when using AutoHotkey v2 with this library include:
1. Functions that find and return windows will often raise an exception rather than returning `None` (as in AutoHotkey v2, a TargetError is thrown in most cases where the window or control cannot be found)
2. The behavior of `ControlSend` (`ahk.control_send` or `Window.send` or `Control.send`) differs in AutoHotkey v2 when the `control` parameter is not specified. In v1, keys are sent to the topmost controls, which is usually the correct behavior. In v2, keys are sent directly to the window. This means in many cases, you need to specify the control explicitly when using V2.
3. Some functionality is not supported in v2 -- specifically: the `secondstowait` paramater for `TrayTip` (`ahk.show_traytip`) was removed in v2. Specifying this parameter in the Python wrapper will cause a warning to be emitted and the parameter is ignored.
4. Some functionality that is present in v1 is not yet implemented in v2 -- this is expected to change in future versions. Specifically: some [sound functions](https://www.autohotkey.com/docs/v2/lib/Sound.htm) are not implemented.
5. The default SendMode changes in v2 to `Input` rather than `Event` in v1 (as a consequence, for example, mouse speed parameters to `mouse_move` and `mouse_drag` will be ignored in V2 unless the send mode is changed)
6. The default [TitleMatchMode](https://www.autohotkey.com/docs/v2/lib/SetTitleMatchMode.htm) is `2` in AutoHotkey v2. It is `1` in AutoHotkey v1. Use the `title_match_mode` keyword arguments to `win_get` and other methods that accept this keyword to control this behavior or use `set_title_match_mode` to change the default behavior (non-blocking calls are run in separate processes and are not affected by `set_title_match_mode`)
## Extending: add your own AutoHotkey code (beta)
You can develop extensions for extending functionality of `ahk` -- that is: writing your own AutoHotkey code and adding
additional methods to the AHK class. See the [extending docs](https://ahk.readthedocs.io/en/latest/extending.html) for
more information.
# Contributing
All contributions are welcomed and appreciated.
Please feel free to open a GitHub issue or PR for feedback, ideas, feature requests or questions.
[winlogo]: http://i.stack.imgur.com/Rfuw7.png
# Similar projects
These are some similar projects that are commonly used for automation with Python.
* [Pyautogui](https://pyautogui.readthedocs.io) - Al Sweigart's creation for cross-platform automation
* [Pywinauto](https://pywinauto.readthedocs.io) - Automation on Windows platforms with Python.
* [keyboard](https://github.com/boppreh/keyboard) - Pure Python cross-platform keyboard hooks/control and hotkeys!
* [mouse](https://github.com/boppreh/mouse) - From the creators of `keyboard`, Pure Python *mouse* control!
* [pynput](https://github.com/moses-palmer/pynput) - Keyboard and mouse control
Raw data
{
"_id": null,
"home_page": "https://github.com/spyoungtech/ahk",
"name": "ahk",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8.0",
"maintainer_email": null,
"keywords": "ahk, autohotkey, windows, mouse, keyboard, automation, pyautogui",
"author": "Spencer Young",
"author_email": "spencer.young@spyoung.com",
"download_url": "https://files.pythonhosted.org/packages/d2/3c/5f35154c5f90197657335f2066c232411ba8334e1d780dbb0783e3b3dd89/ahk-1.8.0.tar.gz",
"platform": null,
"description": "# ahk\n\nA fully typed Python wrapper around AutoHotkey.\n\n[![Docs](https://readthedocs.org/projects/ahk/badge/?version=latest)](https://ahk.readthedocs.io/en/latest/?badge=latest)\n[![Build](https://github.com/spyoungtech/ahk/actions/workflows/test.yaml/badge.svg)](https://github.com/spyoungtech/ahk/actions/workflows/test.yaml)\n[![version](https://img.shields.io/pypi/v/ahk.svg?colorB=blue)](https://pypi.org/project/ahk/)\n[![pyversion](https://img.shields.io/pypi/pyversions/ahk.svg?)](https://pypi.org/project/ahk/)\n[![Coverage](https://coveralls.io/repos/github/spyoungtech/ahk/badge.svg?branch=master)](https://coveralls.io/github/spyoungtech/ahk?branch=master)\n[![Downloads](https://pepy.tech/badge/ahk)](https://pepy.tech/project/ahk)\n\n# Installation\n\n```\npip install ahk\n```\n\nRequires Python 3.8+\n\nSupports AutoHotkey v1 and v2. See also: [Non-Python dependencies](#deps)\n\n# Usage\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.mouse_move(x=100, y=100, blocking=True) # Blocks until mouse finishes moving (the default)\nahk.mouse_move(x=150, y=150, speed=10, blocking=True) # Moves the mouse to x, y taking 'speed' seconds to move\nprint(ahk.mouse_position) # (150, 150)\n```\n\n![ahk](https://raw.githubusercontent.com/spyoungtech/ahk/9d049a327c7a10c9f19dfef89fc63668695023fc/docs/_static/ahk.gif)\n\n# Examples\n\nNon-exhaustive examples of some functions available with this package. See the [full documentation](https://ahk.readthedocs.io/en/latest/?badge=latest)\nfor complete API references and additional features.\n\n## Hotkeys\n\nHotkeys can be configured to run python functions as callbacks.\n\nFor example:\n\n```python\nfrom ahk import AHK\n\ndef my_callback():\n print('Hello callback!')\n\nahk = AHK()\n# when WIN + n is pressed, fire `my_callback`\nahk.add_hotkey('#n', callback=my_callback)\nahk.start_hotkeys() # start the hotkey process thread\nahk.block_forever() # not strictly needed in all scripts -- stops the script from exiting; sleep forever\n```\n\nNow whenever you press <kbd>![Windows Key][winlogo]</kbd> + <kbd>n</kbd>, the `my_callback` callback function will be called in a background thread.\n\nYou can also add an exception handler for your callback:\n\n```python\nfrom ahk import AHK\nahk = AHK()\n\ndef go_boom():\n raise Exception('boom!')\n\ndef my_ex_handler(hotkey: str, exception: Exception):\n print('exception with callback for hotkey', hotkey, 'Here was the error:', exception)\n\nahk.add_hotkey('#n', callback=go_boom, ex_handler=my_ex_handler)\n```\n\nThere are also methods for removing hotkeys:\n\n```python\n# ...\nahk.remove_hotkey('#n') # remove a hotkey by its keyname\nahk.clear_hotkeys() # remove all hotkeys\n```\n\nNote that:\n\n- Hotkeys run in a separate process that must be started manually (with `ahk.start_hotkeys()`)\n- Hotkeys can be stopped with `ahk.stop_hotkeys()` (will not stop actively running callbacks)\n- Hotstrings (discussed below) share the same process with hotkeys and are started/stopped in the same manner\n- If hotkeys or hotstrings are added or removed while the process is running, the underlying AHK process is restarted automatically\n\n\nSee also the [relevant AHK documentation](https://www.autohotkey.com/docs/Hotkeys.htm)\n\n## Hotstrings\n\n\n[Hotstrings](https://www.autohotkey.com/docs/Hotstrings.htm) can also be added to the hotkey process thread.\n\nIn addition to Hotstrings supporting normal AHK string replacements, you can also provide Python callbacks (with optional exception handlers) in response to hotstrings triggering.\n\n```python\nfrom ahk import AHK\nahk = AHK()\n\ndef my_callback():\n print('hello callback!')\n\nahk.add_hotstring('btw', 'by the way') # string replacements\nahk.add_hotstring('btw', my_callback) # call python function in response to the hotstring\n```\n\nYou can also remove hotstrings:\n\n```python\nahk.remove_hotstring('btw') # remove a hotstring by its trigger sequence\nahk.clear_hotstrings() # remove all registered hotstrings\n```\n\n## Mouse\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.mouse_position # Returns a tuple of mouse coordinates (x, y) (relative to active window)\nahk.get_mouse_position(coord_mode='Screen') # get coordinates relative to the screen\nahk.mouse_move(100, 100, speed=10, relative=True) # Moves the mouse reletave to the current position\nahk.mouse_position = (100, 100) # Moves the mouse instantly to absolute screen position\nahk.click() # Click the primary mouse button\nahk.click(200, 200) # Moves the mouse to a particular position and clicks (relative to active window)\nahk.click(100, 200, coord_mode='Screen') # click relative to the screen instead of active window\nahk.click(button='R', click_count=2) # Clicks the right mouse button twice\nahk.right_click() # Clicks the secondary mouse button\nahk.mouse_drag(100, 100, relative=True) # Holds down primary button and moves the mouse\n```\n\n## Keyboard\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.type('hello, world!') # Send keys, as if typed (performs string escapes for you)\nahk.send_input('Hello, {U+1F30E}{!}') # Like AHK SendInput\n # Unlike `type`, control sequences must be escaped manually.\n # For example the characters `!^+#=` and braces (`{` `}`) must be escaped manually.\nahk.key_state('Control') # Return True or False based on whether Control key is pressed down\nahk.key_state('CapsLock', mode='T') # Check toggle state of a key (like for NumLock, CapsLock, etc)\nahk.key_press('a') # Press and release a key\nahk.key_down('Control') # Press down (but do not release) Control key\nahk.key_up('Control') # Release the key\nahk.set_capslock_state(\"On\") # Turn CapsLock on\nif ahk.key_wait('x', timeout=3): # wait for a key to be pressed; returns a boolean\n print('X was pressed within 3 seconds')\nelse:\n print('X was not pressed within 3 seconds')\n```\n\n## Windows\n\nYou can do stuff with windows, too.\n\n\n### Getting windows\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nwin = ahk.active_window # Get the active window\nwin = ahk.win_get(title='Untitled - Notepad') # by title\nall_windows = ahk.list_windows() # list of all windows\nwin = ahk.win_get_from_mouse_position() # the window under the mouse cursor\nwin = ahk.win_get(title='ahk_pid 20366') # get window from pid\n\n# Wait for a window\ntry:\n # wait up to 5 seconds for notepad\n win = ahk.win_wait(title='Untitled - Notepad', timeout=5)\n # see also: win_wait_active, win_wait_not_active\nexcept TimeoutError:\n print('Notepad was not found!')\n```\n\n### Working with windows\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.run_script('Run Notepad') # Open notepad\nwin = ahk.find_window(title='Untitled - Notepad') # Find the opened window; returns a `Window` object\n\n# Window object methods\nwin.send('hello', control='Edit1') # Send keys directly to the window (does not need focus!)\n# OR ahk.control_send(title='Untitled - Notepad', control='Edit1')\nwin.move(x=200, y=300, width=500, height=800)\n\nwin.activate() # Give the window focus\nwin.close() # Close the window\nwin.hide() # Hide the window\nwin.kill() # Kill the window\nwin.maximize() # Maximize the window\nwin.minimize() # Minimize the window\nwin.restore() # Restore the window\nwin.show() # Show the window\nwin.disable() # Make the window non-interactable\nwin.enable() # Enable it again\nwin.to_top() # Move the window on top of other windows\nwin.to_bottom() # Move the window to the bottom of the other windows\nwin.get_class() # Get the class name of the window\nwin.get_minmax() # Get the min/max status\nwin.get_process_name() # Get the process name (e.g., \"notepad.exe\")\nwin.process_name # Property; same as `.get_process_name()` above\nwin.is_always_on_top() # Whether the window has the 'always on top' style applied\nwin.list_controls() # Get a list of controls (list of `Control` objects)\nwin.redraw() # Redraw the window\nwin.set_style(\"-0xC00000\") # Set a style on the window (in this case, removing the title bar)\nwin.set_ex_style(\"^0x80\") # Set an ExStyle on the window (in this case, removes the window from alt-tab list)\nwin.set_region(\"\") # See: https://www.autohotkey.com/docs/v2/lib/WinSetRegion.htm\nwin.set_trans_color(\"White\") # Makes all pixels of the chosen color invisible inside the specified window.\nwin.set_transparent(155) # Makes the specified window semi-transparent (or \"Off\" to turn off transparency)\n\n\nwin.always_on_top = 'On' # Make the window always on top\n# or\nwin.set_always_on_top('On')\n\nfor window in ahk.list_windows(): # list all (non-hidden) windows -- ``detect_hidden_windows=True`` to include hidden\n print(window.title)\n\n # Some more attributes\n print(window.text) # window text -- or .get_text()\n print(window.get_position()) # (x, y, width, height)\n print(window.id) # the ahk_id of the window\n print(window.pid) # process ID -- or .get_pid()\n print(window.process_path) # or .get_process_path()\n\n\nif win.active: # or win.is_active()\n ...\n\nif win.exist: # or win.exists()\n ...\n\n# Controls\n\nedit_control = win.list_controls()[0] # get the first control for the window, in this case \"Edit1\" for Notepad\nedit_control.get_text() # get the text in Notepad\nedit_control.get_position() # returns a `Postion` namedtuple: e.g. Position(x=6, y=49, width=2381, height=1013)\n\n```\n\nVarious window methods can also be called directly without first creating a `Window` object by using the underlying `win_*` methods on the `AHK` class.\nFor example, instead of `win.close()` as above, one could call `ahk.win_close(title='Untitled - Notepad')` instead.\n\n\n\n## Screen\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.image_search('C:\\\\path\\\\to\\\\image.jpg') # Find an image on screen\n\n# Find an image within a boundary on screen\nahk.image_search('C:\\\\path\\\\to\\\\image.jpg', upper_bound=(100, 100), # upper-left corner of search area\n lower_bound=(400, 400)) # lower-right corner of search area\nahk.pixel_get_color(100, 100) # Get color of pixel located at coords (100, 100)\nahk.pixel_search(color='0x9d6346', search_region_start=(0, 0), search_region_end=(500, 500)) # Get coords of the first pixel with specified color\n```\n\n## Clipboard\n\nGet/set `Clipboard` data\n\n```python\nfrom ahk import AHK\nahk = AHK()\n\nahk.set_clipboard('hello \\N{EARTH GLOBE AMERICAS}') # set clipboard text contents\nahk.get_clipboard() # get clipboard text contents\n# 'hello \ud83c\udf0e'\nahk.set_clipboard(\"\") # Clear the clipboard\n\nahk.clip_wait(timeout=3) # Wait for clipboard contents to change (with text or file(s))\nahk.clip_wait(timeout=3, wait_for_any_data=True) # wait for _any_ clipboard contents\n```\n\nYou may also get/set `ClipboardAll` -- however, you should never try to call `set_clipboard_all` with any other\ndata than as _exactly_ as returned by `get_clipboard_all` or unexpected problems may occur.\n\n```python\nfrom ahk import AHK\nahk = AHK()\n\n# save all clipboard contents in all formats\nsaved_clipboard = ahk.get_clipboard_all()\nahk.set_clipboard('something else')\n...\nahk.set_clipboard_all(saved_clipboard) # restore saved content from earlier\n```\n\nYou can also set a callback to execute when the clipboard contents change. As with Hotkey methods mentioned above,\nyou can also set an exception handler. Like hotkeys, `on_clipboard_change` callbacks also require `.start_hotkeys()`\nto be called to take effect.\n\nThe callback function must accept one positional argument, which is an integer indicating the clipboard datatype.\n\n```python\nfrom ahk import AHK\nahk = AHK()\ndef my_clipboard_callback(change_type: int):\n if change_type == 0:\n print('Clipboard is now empty')\n elif change_type == 1:\n print('Clipboard has text contents')\n elif change_type == 2:\n print('Clipboard has non-text contents')\n\nahk.on_clipboard_change(my_clipboard_callback)\nahk.start_hotkeys() # like with hotkeys, must be called at least once for listening to start\n# ...\nahk.set_clipboard(\"hello\") # will cause the message \"Clipboard has text contents\" to be printed by the callback\nahk.set_clipboard(\"\") # Clears the clipboard, causing the message \"Clipboard is now empty\" to be printed by the callback\n```\n\n## Sound\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.sound_play('C:\\\\path\\\\to\\\\sound.wav') # Play an audio file\nahk.sound_beep(frequency=440, duration=1000) # Play a beep for 1 second (duration in microseconds)\nahk.get_volume(device_number=1) # Get volume of a device\nahk.set_volume(50, device_number=1) # Set volume of a device\nahk.sound_get(device_number=1, component_type='MASTER', control_type='VOLUME') # Get sound device property\nahk.sound_set(50, device_number=1, component_type='MASTER', control_type='VOLUME') # Set sound device property\n```\n\n## GUI\n\n\nTooltips/traytips\n\n```python\nimport time\nfrom ahk import AHK\n\nahk = AHK()\nahk.show_tooltip(\"hello4\", x=10, y=10)\ntime.sleep(2)\nahk.hide_tooltip() # hide the tooltip\nahk.show_info_traytip(\"Info\", \"It's also info\", silent=False, blocking=True) # Default info traytip\nahk.show_warning_traytip(\"Warning\", \"It's a warning\") # Warning traytip\nahk.show_error_traytip(\"Error\", \"It's an error\") # Error trytip\n```\n\nDialog boxes\n\n```python\nfrom ahk import AHK, MsgBoxButtons\nahk = AHK()\n\nahk.msg_box(text='Do you like message boxes?', title='My Title', buttons=MsgBoxButtons.YES_NO)\nahk.input_box(prompt='Password', title='Enter your password', hide=True)\nahk.file_select_box(title='Select one or more mp3 files', multi=True, filter='*.mp3', file_must_exist=True)\nahk.folder_select_box(prompt='Select a folder')\n```\n\n## Global state changes\n\nYou can change various global states such as `CoordMode`, `DetectHiddenWindows`, etc. so you don't have to pass\nthese parameters directly to function calls\n\n```python\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.set_coord_mode('Mouse', 'Screen') # set default Mouse CoordMode to be relative to Screen\nahk.set_detect_hidden_windows(True) # Turn on detect hidden windows by default\nahk.set_send_level(5) # Change send https://www.autohotkey.com/docs/v1/lib/SendLevel.htm\n\nahk.set_title_match_mode('Slow') # change title match speed and/or mode\nahk.set_title_match_mode('RegEx')\nahk.set_title_match_mode(('RegEx', 'Slow')) # or both at the same time\nahk.set_send_mode('Event') # change the default SendMode\n```\n\n## Add directives\n\nYou can add directives that will be added to all generated scripts.\nFor example, to prevent the AHK trayicon from appearing, you can add the NoTrayIcon directive.\n\n```python\nfrom ahk import AHK\nfrom ahk.directives import NoTrayIcon\n\nahk = AHK(directives=[NoTrayIcon])\n```\n\nBy default, some directives are automatically added to ensure functionality and are merged with any user-provided directives.\n\nDirectives are not applied for the AHK process used for handling hotkeys and hotstrings (discussed below) by default. To apply a directive\nto the hotkeys process using the keyword argument `apply_to_hotkeys_process=True`:\n\n```python\nfrom ahk import AHK\nfrom ahk.directives import NoTrayIcon\n\ndirectives = [\n NoTrayIcon(apply_to_hotkeys_process=True)\n]\n\nahk = AHK(directives=directives)\n```\n\n## Menu tray icon\n\nAs discussed above, you can hide the tray icon if you wish. Additionally, there are some methods available for\ncustomizing the tray icon.\n\n\n```python\nfrom ahk import AHK\nahk = AHK()\n\n# change the tray icon (in this case, using a builtin system icon)\nahk.menu_tray_icon('Shell32.dll', 174)\n# revert it back to the original:\nahk.menu_tray_icon()\n\n# change the tooltip that shows up when hovering the mouse over the tray icon\nahk.menu_tray_tooltip('My Program Name')\n\n# Hide the tray icon\nahk.menu_tray_icon_hide()\n\n# Show the tray icon that was previously hidden by ``NoTrayIcon`` or ``menu_tray_icon_hide``\nahk.menu_tray_icon_show()\n```\n\n## Registry methods\n\nYou can read/write/delete registry keys:\n\n```python\nfrom ahk import AHK\nahk = AHK()\n\nahk.reg_write('REG_SZ', r'HKEY_CURRENT_USER\\SOFTWARE\\my-software', value='test')\nahk.reg_write('REG_SZ', r'HKEY_CURRENT_USER\\SOFTWARE\\my-software', value_name='foo', value='bar')\nahk.reg_read(r'HKEY_CURRENT_USER\\SOFTWARE\\my-software') # 'test'\nahk.reg_delete(r'HKEY_CURRENT_USER\\SOFTWARE\\my-software')\n```\n\nIf a key does not exist or some other problem occurs, an exception is raised.\n\n## non-blocking modes\n\nMost methods in this library supply a non-blocking interface, so your Python scripts can continue executing while\nyour AHK scripts run.\n\nBy default, all calls are _blocking_ -- each function will execute completely before the next function is ran.\n\nHowever, sometimes you may want to run other code while AHK executes some code. When the `blocking` keyword\nargument is supplied with `False`, function calls will return immediately while the AHK function is carried out\nin the background.\n\n\nAs an example, you can move the mouse slowly and report its position as it moves:\n\n```python\nimport time\n\nfrom ahk import AHK\n\nahk = AHK()\n\nahk.mouse_position = (200, 200) # Moves the mouse instantly to the start position\nstart = time.time()\n\n# move the mouse very slowly\nahk.mouse_move(x=100, y=100, speed=30, blocking=False)\n\n# This code begins executing right away, even though the mouse is still moving\nwhile True:\n t = round(time.time() - start, 4)\n position = ahk.mouse_position\n print(t, position) # report mouse position while it moves\n if position == (100, 100):\n break\n```\n\n\nWhen you specify `blocking=False` you will always receive a special `FutureResult` object (or `AsyncFutureResult` object in the async API, discussed below)\nwhich allows you to wait on the function to complete and retrieve return value through a `get_result` function. Even\nwhen a function normally returns `None`, this can be useful to ensure AHK has finished executing the function.\n\nnonblocking calls:\n\n- Are isolated in a new AHK process that will terminate after the call is complete\n- Always start immediately\n- Do not inherit previous global state changes (e.g., from `set_coord_mode` calls or similar) -- this may change in a future version.\n- will not block other calls from starting\n- will always return a special `FutureResult` object (or `AsyncFutureResult` object in the async API, discussed below)\nwhich allows you to wait on the function to complete and retrieve return value through the `result` function. Even\nwhen a function normally returns `None`, this can be useful to ensure AHK has finished executing the function.\n\n```python\nfrom ahk import AHK\nahk = AHK()\nfuture_result = ahk.mouse_move(100, 100, speed=40, blocking=False)\n...\n# wait on the mouse_move to finish\nfuture_result.result(timeout=10) # timeout keyword is optional\n```\n\n\n\n## Async API (asyncio)\n\nAn async API is provided so functions can be called using `async`/`await`.\nAll the same methods from the synchronous API are available in the async API.\n\n```python\nfrom ahk import AsyncAHK\nimport asyncio\nahk = AsyncAHK()\n\nasync def main():\n await ahk.mouse_move(100, 100)\n x, y = await ahk.get_mouse_position()\n print(x, y)\n\nasyncio.run(main())\n```\n\nThe async API is identical to that of the normal API, with a few notable differences:\n\n- While properties (like `.mouse_position` or `.title` for windows) can be `await`ed,\nadditional methods (like `get_mouse_position()` and `get_title()`) have been added for a more intuitive API and\nare recommended over the use of properties.\n- Property _setters_ (e.g., `ahk.mouse_postion = (200, 200)`) are not allowed in the async API (a RunTimeError is raised).\nProperty setters remain available in the sync API.\n- `AsyncFutureResult` objects (returned when specifying `blocking=False`) work the same as the `FutureResult` objects in the sync API, except the `timeout` keyword is not supported for the `result` method).\n\nNote also that:\n- by default, awaited tasks on a single `AsyncAHK` instance will not run concurrently. You must either\nuse `blocking=False`, as in the sync API, or use multiple instances of `AsyncAHK`.\n- There is no difference in working with hotkeys (and their callbacks) in the async vs sync API.\n\n\n## type-hints and mypy\n\nThis library is fully type-hinted, allowing you to leverage tools like `mypy` to help validate the type-correctness\nof your code. IDEs that implement type-checking features are also able to leverage type hints to help ensure your\ncode is safe.\n\n\n## Run arbitrary AutoHotkey scripts\n\nYou can also run arbitrary AutoHotkey code either as a `.ahk` script file or as a string containing AHK code.\n\n```python\nfrom ahk import AHK\nahk = AHK()\nmy_script = '''\\\nMouseMove, 100, 100\n; etc...\n'''\n\nahk.run_script(my_script)\n```\n\n```python\nfrom ahk import AHK\nahk = AHK()\nscript_path = r'C:\\Path\\To\\myscript.ahk'\nahk.run_script(script_path)\n```\n\n\n<a name=\"deps\"></a>\n\n# Non-Python dependencies\n\nTo use this package, you need the [AutoHotkey executable](https://www.autohotkey.com/download/) (e.g., `AutoHotkey.exe`).\nIt's expected to be on PATH by default OR in a default installation location (`C:\\Program Files\\AutoHotkey\\AutoHotkey.exe` for v1 or `C:\\Program Files\\AutoHotkey\\v2\\AutoHotkey64.exe` for v2)\n\nAutoHotkey v1 and v2 are both fully supported, though some behavioral differences will occur depending on which version\nyou use. See notes below.\n\nThe recommended way to supply the AutoHotkey binary (for both v1 and v2) is to install the `binary` extra for this package. This will\nprovide the necessary executables and help ensure they are correctly placed on PATH.\n\n```\npip install \"ahk[binary]\"\n```\n\n\nAlternatively, you may provide the path in code:\n\n```python\nfrom ahk import AHK\n\nahk = AHK(executable_path='C:\\\\path\\\\to\\\\AutoHotkey.exe')\n```\n\nYou can also use the `AHK_PATH` environment variable to specify the executable location.\n\n```console\nset AHK_PATH=C:\\Path\\To\\AutoHotkey.exe\npython myscript.py\n```\n\n## Using AHK v2\n\nBy default, when no `executable_path` parameter (or `AHK_PATH` environment variable) is set, only AutoHotkey v1 binary names\nare searched for on PATH or default install locations. This behavior may change in future versions to allow v2 to be used by default.\n\nTo use AutoHotkey version 2, you can do any of the following things:\n\n1. provide the `executable_path` keyword argument with the location of the AutoHotkey v2 binary\n2. set the `AHK_PATH` environment variable with the location of an AutoHotkey v2 binary\n3. Provide the `version` keyword argument with the value `v2` which enables finding the executable using AutoHotkey v2 binary names and default install locations.\n\nFor example:\n\n```python\nfrom ahk import AHK\n\n\nahk = AHK(executable_path=r'C:\\Program Files\\AutoHotkey\\v2\\AutoHotkey64.exe')\n# OR\nahk = AHK(version='v2')\n```\n\nWhen you provide the `version` keyword argument (with either `\"v1\"` or `\"v2\"`) a check is performed to ensure the provided (or discovered) binary matches the requested version. When\nthe `version` keyword is omitted, the version is determined automatically from the provided (or discovered) executable binary.\n\n\n\n### Differences when using AutoHotkey v1 vs AutoHotkey v2\n\nThe API of this project is originally designed against AutoHotkey v1 and function signatures are the same, even when using AutoHotkey v2.\nWhile most of the behavior remains the same, some behavior does change when using AutoHotkey v2 compared to v1. This is mostly due to\n[underlying differences](https://www.autohotkey.com/docs/v2/v2-changes.htm) between the two versions.\n\nSome of the notable differences that you may experience when using AutoHotkey v2 with this library include:\n\n1. Functions that find and return windows will often raise an exception rather than returning `None` (as in AutoHotkey v2, a TargetError is thrown in most cases where the window or control cannot be found)\n2. The behavior of `ControlSend` (`ahk.control_send` or `Window.send` or `Control.send`) differs in AutoHotkey v2 when the `control` parameter is not specified. In v1, keys are sent to the topmost controls, which is usually the correct behavior. In v2, keys are sent directly to the window. This means in many cases, you need to specify the control explicitly when using V2.\n3. Some functionality is not supported in v2 -- specifically: the `secondstowait` paramater for `TrayTip` (`ahk.show_traytip`) was removed in v2. Specifying this parameter in the Python wrapper will cause a warning to be emitted and the parameter is ignored.\n4. Some functionality that is present in v1 is not yet implemented in v2 -- this is expected to change in future versions. Specifically: some [sound functions](https://www.autohotkey.com/docs/v2/lib/Sound.htm) are not implemented.\n5. The default SendMode changes in v2 to `Input` rather than `Event` in v1 (as a consequence, for example, mouse speed parameters to `mouse_move` and `mouse_drag` will be ignored in V2 unless the send mode is changed)\n6. The default [TitleMatchMode](https://www.autohotkey.com/docs/v2/lib/SetTitleMatchMode.htm) is `2` in AutoHotkey v2. It is `1` in AutoHotkey v1. Use the `title_match_mode` keyword arguments to `win_get` and other methods that accept this keyword to control this behavior or use `set_title_match_mode` to change the default behavior (non-blocking calls are run in separate processes and are not affected by `set_title_match_mode`)\n\n## Extending: add your own AutoHotkey code (beta)\n\nYou can develop extensions for extending functionality of `ahk` -- that is: writing your own AutoHotkey code and adding\nadditional methods to the AHK class. See the [extending docs](https://ahk.readthedocs.io/en/latest/extending.html) for\nmore information.\n\n# Contributing\n\nAll contributions are welcomed and appreciated.\n\nPlease feel free to open a GitHub issue or PR for feedback, ideas, feature requests or questions.\n\n[winlogo]: http://i.stack.imgur.com/Rfuw7.png\n\n\n# Similar projects\n\nThese are some similar projects that are commonly used for automation with Python.\n\n* [Pyautogui](https://pyautogui.readthedocs.io) - Al Sweigart's creation for cross-platform automation\n* [Pywinauto](https://pywinauto.readthedocs.io) - Automation on Windows platforms with Python.\n* [keyboard](https://github.com/boppreh/keyboard) - Pure Python cross-platform keyboard hooks/control and hotkeys!\n* [mouse](https://github.com/boppreh/mouse) - From the creators of `keyboard`, Pure Python *mouse* control!\n* [pynput](https://github.com/moses-palmer/pynput) - Keyboard and mouse control\n",
"bugtrack_url": null,
"license": null,
"summary": "A Python wrapper for AHK",
"version": "1.8.0",
"project_urls": {
"Documentation": "https://ahk.readthedocs.io/en/latest/",
"Funding": "https://github.com/sponsors/spyoungtech/",
"Homepage": "https://github.com/spyoungtech/ahk",
"Source": "https://github.com/spyoungtech/ahk",
"Tracker": "https://github.com/spyoungtech/ahk/issues"
},
"split_keywords": [
"ahk",
" autohotkey",
" windows",
" mouse",
" keyboard",
" automation",
" pyautogui"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "877f1ed8df77c1fe54f0a9d3c9df60c547b8a646490d1730b7494efce6e6f9f4",
"md5": "faf46b12bf3f8a8f7768bfecdebeac59",
"sha256": "0947b09d35b1d43c6c7da6bd6fb90acd05b7ab2e7bc918c8238e0533495ef74e"
},
"downloads": -1,
"filename": "ahk-1.8.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "faf46b12bf3f8a8f7768bfecdebeac59",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8.0",
"size": 123843,
"upload_time": "2024-08-17T22:09:56",
"upload_time_iso_8601": "2024-08-17T22:09:56.934676Z",
"url": "https://files.pythonhosted.org/packages/87/7f/1ed8df77c1fe54f0a9d3c9df60c547b8a646490d1730b7494efce6e6f9f4/ahk-1.8.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d23c5f35154c5f90197657335f2066c232411ba8334e1d780dbb0783e3b3dd89",
"md5": "d482aca35df90884fd5e2e2d8dcc956b",
"sha256": "0fbd2dc71566d60d13326238347109f591119a1338a35baa6a473c5c3d7ec20c"
},
"downloads": -1,
"filename": "ahk-1.8.0.tar.gz",
"has_sig": false,
"md5_digest": "d482aca35df90884fd5e2e2d8dcc956b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8.0",
"size": 132678,
"upload_time": "2024-08-17T22:09:59",
"upload_time_iso_8601": "2024-08-17T22:09:59.024696Z",
"url": "https://files.pythonhosted.org/packages/d2/3c/5f35154c5f90197657335f2066c232411ba8334e1d780dbb0783e3b3dd89/ahk-1.8.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-17 22:09:59",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "spyoungtech",
"github_project": "ahk",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"tox": true,
"lcname": "ahk"
}