Giter Club home page Giter Club logo

ahk's Introduction

ahk

A fully typed Python wrapper around AutoHotkey.

Docs Build version pyversion Coverage Downloads

Installation

pip install ahk

Requires Python 3.8+

Supports AutoHotkey v1 and v2. See also: Non-Python dependencies

Usage

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

Examples

Non-exhaustive examples of some functions available with this package. See the full documentation for complete API references and additional features.

Hotkeys

Hotkeys can be configured to run python functions as callbacks.

For example:

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 Windows Key + n, the my_callback callback function will be called in a background thread.

You can also add an exception handler for your callback:

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:

# ...
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

Hotstrings

Hotstrings 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.

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:

ahk.remove_hotstring('btw')  # remove a hotstring by its trigger sequence
ahk.clear_hotstrings()  # remove all registered hotstrings

Mouse

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

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

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

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

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

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.

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.

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

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

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

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

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.

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:

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.

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:

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:

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.
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.

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 awaited, 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.

from ahk import AHK
ahk = AHK()
my_script = '''\
MouseMove, 100, 100
; etc...
'''

ahk.run_script(my_script)
from ahk import AHK
ahk = AHK()
script_path = r'C:\Path\To\myscript.ahk'
ahk.run_script(script_path)

Non-Python dependencies

To use this package, you need the AutoHotkey executable (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:

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.

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:

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 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 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 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 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.

Similar projects

These are some similar projects that are commonly used for automation with Python.

  • Pyautogui - Al Sweigart's creation for cross-platform automation
  • Pywinauto - Automation on Windows platforms with Python.
  • keyboard - Pure Python cross-platform keyboard hooks/control and hotkeys!
  • mouse - From the creators of keyboard, Pure Python mouse control!
  • pynput - Keyboard and mouse control

ahk's People

Contributors

dizzythermal avatar filantus avatar forestsource avatar glutenberg avatar nickiel12 avatar pestitschek avatar pre-commit-ci[bot] avatar spatiag avatar spyoungtech avatar yemreak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ahk's Issues

return None instead of empty string

Sometimes functions will return an empty string when they should probably be returning None instead. This is because they are doing return self.run_script(...) but the script doesn't return any value. It will be better if these were all consistent and returned None instead.

AHK string escaping

Need a way to help make strings 'safe' for keyboard typing functionality.
I'm thinking something similar to Jinja's HTML escaping.

I don't think we can guarantee safety against malicious/untrusted inputs, but it should behave well with all common characters.

Feature/Hotkeys

Not sure what interface I want hotkeys to take.

keyboard is a project that offers cross-platform hotkeys and keyboard actions.

Not sure if to model after keyboard or do something else.

Here's a quick mockup I have in mind

myhotkey = Hotkey('CTRL+T', some_script)
myhotkey.start()  #  start the process with the hotkey trigger (e.g. listening in the background)
myhotkey.stop()  #  stop the script

Where some_script would be an ahk script to put under the hotkey declaration.

Another possible idea would be to have hotkeys have the ability to perform callbacks for Python functions, similar to keyboard, but I can't think of a great way to accomplish this at the moment.

Getting script output before closing it. [Not issue, just asking for help]

How i can run script that returns information to python before exiting?
For example, i run python script that shows nothing in console and starts AHK script with GUI button. Then i press this button and python console shows me "pressed!". Then i press it again and "pressed!" appears second time in python console. Then i close GUI and python script finishes itself.

I did something, but my example does not works.

from ahk import AHK
from ahk.window import Window

gui = """
#SingleInstance, force
#NoTrayIcon
#Persistent

Gui, bfb:Add, Button, x5 y5 w140 h90 gBigButton, DON'T PRESS
Gui, bfb:Show, w150 h100, lmao
Gui, bfb:-MinimizeBox
return

BigButton:
FileAppend, "Button pressed!", *
return

bfbGuiClose:
ExitApp
"""

def main():
	try:
		ahk = AHK(executable_path="AutoHotkey.exe")
	except:
		return

	print("Starting getting information from script!")
	result = ahk.run_script(gui, blocking=False)
	while True:
		print(result.stdout)

if __name__ == '__main__':
	main()

German umlaute with python 3.7+ not working as expected

Hello,
i try to write a script that writes ingame item names in the chat, but all umlauts are displayed funny (e.g. http://i.gyazo.com/3df9910aff56e821f362e6a88f084acf.png). does anyone know how i can solve this problem?
I use Windows 10 and have the Unicode 64 bit version of AHK v1.1.32.00.

When I execute the following code I get the character ü in game, but I expect ü
(I Have a German keyboard and layout in Windows!)

ahk.send_input("ü")

Execute Python functions in response to Hotkeys

Right now, HotKeys only support running autohotkey code. It would be nice if we could figure out how it may be possible to hook executing Python functions in response to a hotkey being pressed.

For anyone looking for this functionality in the meantime, I recommend using the keyboard library.

Using AHK functions?

Is there a way to use something like this?
FileAppend, % Clipboard "n", C:\file.txt`

Add nonblocking functionality for more functions

There are some functions right now that can reasonably be run in a nonblocking mode which currently don't accept a blocking keyword argument. The keyword should be added for these functions.

How to stop ahk script in mid run?

I am trying to write a hotkey class version that binds functions to hotkeys. (https://github.com/Nickiel12/ahk/tree/Bindable-Hotkeys) My question is, is there a way to stop a running script? Or listen for a hotkey and exit after 3 seconds? I am using file write to see if the hotkey had been pressed. My problem is when I try to shut it down, the script doesn't stop till the hotkey is pressed and exitapp is called.

Image_search - ValueError: malformed node or string: None

File "c:/Users/rrajpuro/Documents/Macros/test.py", line 6, in run
ac.image_search("C:\Users\rrajpuro\Pictures\War.JPG")
File "C:\Users\rrajpuro\AppData\Local\Programs\Python\Python37-32\lib\site-packages\ahk\screen.py", line 74, in image_search
return ast.literal_eval(resp)
File "C:\Users\rrajpuro\AppData\Local\Programs\Python\Python37-32\lib\ast.py", line 91, in literal_eval
return _convert(node_or_string)
File "C:\Users\rrajpuro\AppData\Local\Programs\Python\Python37-32\lib\ast.py", line 90, in _convert
return _convert_signed_num(node)
File "C:\Users\rrajpuro\AppData\Local\Programs\Python\Python37-32\lib\ast.py", line 63, in _convert_signed_num
return _convert_num(node)
File "C:\Users\rrajpuro\AppData\Local\Programs\Python\Python37-32\lib\ast.py", line 55, in _convert_num
raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: None

Misconfigured path causes PermissionError within subprocess.Popen call

python runned from cmd with admin privileges.
running any action, e.g. ahk.mouse_move(x=100, y=100, speed=30, blocking=False)
will throw PermissionError:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python\Python37\lib\site-packages\ahk\mouse.py", line 89, in mouse_move
    self.run_script(script, blocking=blocking)
  File "C:\Python\Python37\lib\site-packages\ahk\script.py", line 76, in run_script
    result = self._run_script(script_text, decode=decode, blocking=blocking, **runkwargs)
  File "C:\Python\Python37\lib\site-packages\ahk\script.py", line 66, in _run_script
    proc = subprocess.Popen(runargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
  File "C:\Python\Python37\lib\subprocess.py", line 775, in __init__
    restore_signals, start_new_session)
  File "C:\Python\Python37\lib\subprocess.py", line 1178, in _execute_child
    startupinfo)
PermissionError: [WinError 5] Access is denied

Checking permissions from PowerShell:

PS D:\Prog\AutoHotkey> Get-Acl | fl


Path   : Microsoft.PowerShell.Core\FileSystem::D:\Prog\AutoHotkey
Owner  : BUILTIN\Administrators
Group  : G:S-1-5-21-1413140394-118887914-2539411025-513
Access : Все Allow  FullControl
         NT AUTHORITY\SYSTEM Allow  FullControl
         S-1-5-21-1413140394-118887914-2539411025-1000 Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:BAG:S-1-5-21-1413140394-118887914-2539411025-513D:AI(A;OICIID;FA;;;WD)(A;OICIID;FA;;;SY)(A;OICIID;FA;;;S-1-5
         -21-1413140394-118887914-2539411025-1000)(A;OICIID;FA;;;BA)



PS D:\Prog\AutoHotkey> Dir | Get-Acl | fl
...
Path   : Microsoft.PowerShell.Core\FileSystem::D:\Prog\AutoHotkey\AutoHotkey.exe
Owner  : BUILTIN\Administrators
Group  : G:S-1-5-21-1413140394-118887914-2539411025-513
Access : Все Allow  FullControl
         NT AUTHORITY\SYSTEM Allow  FullControl
         S-1-5-21-1413140394-118887914-2539411025-1000 Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:BAG:S-1-5-21-1413140394-118887914-2539411025-513D:AI(A;ID;FA;;;WD)(A;ID;FA;;;SY)(A;ID;FA;;;S-1-5-21-14131403
         94-118887914-2539411025-1000)(A;ID;FA;;;BA)

Path   : Microsoft.PowerShell.Core\FileSystem::D:\Prog\AutoHotkey\AutoHotkeyA32.exe
Owner  : BUILTIN\Administrators
Group  : G:S-1-5-21-1413140394-118887914-2539411025-513
Access : Все Allow  FullControl
         NT AUTHORITY\SYSTEM Allow  FullControl
         S-1-5-21-1413140394-118887914-2539411025-1000 Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:BAG:S-1-5-21-1413140394-118887914-2539411025-513D:AI(A;ID;FA;;;WD)(A;ID;FA;;;SY)(A;ID;FA;;;S-1-5-21-14131403
         94-118887914-2539411025-1000)(A;ID;FA;;;BA)

Path   : Microsoft.PowerShell.Core\FileSystem::D:\Prog\AutoHotkey\AutoHotkeyU32.exe
Owner  : BUILTIN\Administrators
Group  : G:S-1-5-21-1413140394-118887914-2539411025-513
Access : Все Allow  FullControl
         NT AUTHORITY\SYSTEM Allow  FullControl
         S-1-5-21-1413140394-118887914-2539411025-1000 Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:BAG:S-1-5-21-1413140394-118887914-2539411025-513D:AI(A;ID;FA;;;WD)(A;ID;FA;;;SY)(A;ID;FA;;;S-1-5-21-14131403
         94-118887914-2539411025-1000)(A;ID;FA;;;BA)

Path   : Microsoft.PowerShell.Core\FileSystem::D:\Prog\AutoHotkey\AutoHotkeyU64.exe
Owner  : BUILTIN\Administrators
Group  : G:S-1-5-21-1413140394-118887914-2539411025-513
Access : Все Allow  FullControl
         NT AUTHORITY\SYSTEM Allow  FullControl
         S-1-5-21-1413140394-118887914-2539411025-1000 Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:BAG:S-1-5-21-1413140394-118887914-2539411025-513D:AI(A;ID;FA;;;WD)(A;ID;FA;;;SY)(A;ID;FA;;;S-1-5-21-14131403
         94-118887914-2539411025-1000)(A;ID;FA;;;BA)
...

It's looks like need to run subprocess from admin privileges as well.
For this need to add to subprosess.Popen these args before running AutoHotkey.exe executable:

'runas', '/noprofile', '/user:Administrator',

Feature/GUI

Implement GUI interface. REF: https://www.autohotkey.com/docs/commands/Gui.htm

  • FileSelectFile
  • FileSelectFolder
  • Gui
  • Gui control types
  • [ ]GuiControl
  • GuiControlGet
  • Gui ListView control
  • Gui TreeView control
  • IfMsgBox
  • Image Handles
  • InputBox
  • LoadPicture
  • Menu
  • MenuGetHandle
  • MenuGetName
  • MsgBox
  • OnMessage
  • Progress
  • SplashImage
  • SplashTextOn/SplashTextOff
  • Standard Windows Fonts
  • Styles for a window/control
  • ToolTip

How to check specific radius of pixels?

In ahk you can search pixel in specific radius of pixels, but in python ahk you can search in only one pixel.

PixelSearch, Px, Py, 679, 380, 687, 388, 0x00008C, 1, Fast
ahk.pixel_search('0x00008C')
Is there any way to check radius, but not a pixel?

Sorry for bad english, it's not my native language..

Simplify wingets; use ahk_id to track windows

Need to come up with the most conscience way to identify and track windows.

Current implementation is crude and incomplete. Would like the Window class to track its own ahk_id as a better mechanism for making sure we keep accessing the same window.

Trying to acquire pixel color raises WinError 5

Seems to be a permission related issue.
Unsure how to fix this.

Simple code ran from PyCharm:

from ahk import AHK

ahk = AHK(executable_path='C:\\Program Files\\AutoHotkey')
a = ahk.pixel_get_color(2, 2)
print(a)

Compile scripts?

Wondering if the ActionChain implementation (#25) could be changed to support creating a single script that could then be compiled into an exe. Maybe a compile method that produces an exe that should, more or less, be the same as using the .perform method when executed.

An interface for this might look like

ac = ActionChain()
ac.mouse_drag(size, 0, relative=True)
ac.mouse_drag(0, size, relative=True)
ac.mouse_drag(size * -1, 0, relative=True)
ac.mouse_drag(0, size*-1, relative=True)
ac.compile('draw_square.exe')

Case while Set up mouse keys

Hello,
I got little issue when I started using mouse on keypad ala 'Set up Mouse Keys' on windows.
On key Number5 it listen to mouse click, in real world.
In Ahk it send me back numer 5, meaning - type in number instead of pressing Number5 and click down mouse.
Do you know any workaround for this issue?

feature/winMove

Implement winmove functionality

Ref: https://www.autohotkey.com/docs/commands/WinMove.htm

Probably the interface for this would be something like how mouse moves, except you'd use a particular Window object

win = ahk.active_window
win.move(200, 200)  # moves upper-left-hand corner to (200, 200)

This also includes altering the width/height of a window. This could be additional arguments for a move method. Additionally property setters for width and height should also be implemented

win.move(200, 200, width=500, height=700)  #  move and additionally adjust width/height 
win.width = 500  # sets window width to 500px
win.height = 700  # sets window height to 700px

find window methods

Something analogous to selenium's find_element_by methods or BeautifulSoup's find/find_all methods.

I think the API will also be similar with window Controls.

Send script as stdin

Currently, a tempfile is written to disk before calling the AutoHotkey executable, passing along the tempfile path.

Since AHK 1.1.17 -- scripts can be provided with stdin.

Specify an asterisk (*) for the filename to read the script text from standard input (stdin). For an example, see ExecScript().

So, we should do this instead as it removed the overhead of writing to (and AHK subsequently reading from) the physical disk.

Missing Directives

Currently the directives implementations are incomplete. Particularly, directives which take in parameters are not fully implemented.

I think defaults for arguments should be the same as in AutoHotkey, unless a good argument can be made for a more sensible default. We may also opt to provide defaults where AutoHotkey does not.

Anything that is deprecated, not recommended, or being removed in AutoHotkey v2.0 should not be implemented.

How to stop a thread at the end of a program

Any ideas? I have, basically, an infinite poll loop thread that has a while stop_thread == False: , and that works fine, but that means that to close the program, I would have to call a close/cleanup function that changes the stop_thread variable. But I don't know how else to do it. I need the loop, but I would like to keep it simple and not have to call any cleanup function at the end of the program.

I ran into this problem when I was testing the modified module in the cmd prompt and I couldn't stop the program because when I called quit(), the loop would continue.

How to execute frozen script as exe with PyInstaller? TemplateNotFound

Error while trying to execute script freezed to exe with pyinstaller:
Traceback (most recent call last):
File "autoLogin.py", line 4, in
File "site-packages\ahk\mouse.py", line 88, in mouse_move
File "site-packages\ahk\mouse.py", line 84, in _mouse_move
File "site-packages\ahk\script.py", line 49, in render_template
File "site-packages\jinja2\environment.py", line 830, in get_template
File "site-packages\jinja2\environment.py", line 804, in _load_template
File "site-packages\jinja2\loaders.py", line 113, in load
File "site-packages\jinja2\loaders.py", line 187, in get_source
jinja2.exceptions.TemplateNotFound: mouse/mouse_move.ahk
[12584] Failed to execute script autoLogin

communication decoding

I am using the win32 to get a windows event when a file changes. I need some help with a design decision. What happens in the below code is as follows

  1. initiate class
  2. define a win32 event and start a loop to get events
  3. when it gets an event.... aaaand here is where I get stuck.

I need help choosing which of the following to use. Do I have one file that all ahk scripts write to with each hotkey writing an identifying code to the file, and check the most recent code to a dict etc. Or do I make a separate file for every hotkey with the hotkey code in the name and trigger the last_edited_event.

The First Choice
Ups - one file, simpler
downs - complex(er) decoding, long uses of the program with frequent use could lead to large files because if I delete the last hotkey-code, it might accidentally block a hotkey write. (Though, admittedly, this is less of a concern than it could be, depending how python handles opening and reading files)

The Second Choice
Ups - read/writes are simpler, decoding is simpler
downs - finding the changed file could be resource intensive as all files have to be checked

So it comes down to, Large files from extended runs VS large CPU usage when a lot of ahk communication files are present.

PS. Same thing but another system for live data transfer like your "filewrite *"

`
class Abstract_Communicator(metaclass=abc.ABCMeta):

def __init__(self, directory:str):

    if directory == None:
        self.path = pathlib.Path(os.path.abspath(".")) / "tmp"
    else:
        if type(directory) != str: 
            raise TypeError(f"Expected type str, but got type {type(directory)}")
        
        self.path = pathlib.Path(directory)
    if not self.path.exists():
        raise FileNotFoundError(f"The directory or file at {self.path} doesn't exist")
    
    self.stop_thread = False
    self.thread = threading.Thread(target=self.event_loop)
    self.thread.start()

def __del__(self):
    self.stop_thread = True  

@abc.abstractmethod
def on_event(self):
    print("An event!!!")

def event_loop(self):
    change_handle = win32file.FindFirstChangeNotification (
    str(self.path),
    0,
    win32con.FILE_NOTIFY_CHANGE_LAST_WRITE
    )

    try:
        while self.stop_thread == False:
            result = win32event.WaitForSingleObject (change_handle, 500)

            #
            # If the WaitFor... returned because of a notification (as
            #  opposed to timing out or some error) then look for the
            #  changes in the directory contents.
            #
            if result == win32con.WAIT_OBJECT_0:
                self.on_event()
            win32file.FindNextChangeNotification (change_handle)

    finally:
        win32file.FindCloseChangeNotification (change_handle)

class EventListener(Abstract_Communicator):

def on_event(self):
    #this isn't totally implemented
    return super().on_event()

`

NoModuleFoundError?

I'm not really sure where to ask such a dumb, beginner question... but this module looks awesome and I need help with the initial set up.

Directory
venv /
---------- Include /
---------- Lib /
-------------------- site-packages /
---------------------------------------- ahk /
---------------------------------------- (all of my various pip installs here) /
---------- Scripts /
MyPythonFile.py

When I try to import ahk within MyPythonFile.py, I get a ModuleNotFoundError: no module named 'ahk'
When I try to import any other module that I've installed via pip, it works fine.
Example: import requests, works just fine

Other information:

  • I'm using Spyder as my IDE,
  • I can import and use ahk when I do .\venv\Scripts\activate and then run python from within the Windows cmd line.

What am I doing wrong?

Thank you for any help.

Templating engine; Jinja2?

Currently, ahk scripts fed to AutoHotkey are written inline and values are simply substituted using str.format.

The goal is to move towards something of a django-like templating system. Ideally that means users can easily override/extend default .ahk templates. The internal interface would maybe look something like script = render_template('templates/mouse/move_mouse.ahk')

Not sure if Jinja2 is the right tool for this or not, but it's probably my first choice at the moment.

This project needs documentation

Methods need docstrings.

Want to also produce some documentation in the form of sphinx + autodoc to be published via readthedocs.

Contribution, how to ask questions about syntax and naming schemes

How should I go about asking questions about things like syntax, code requirements, what should/shouldn't be added, etc, if I want to contribute. Questions like this one.

I think I might have found a great solution for ahk->python communication, but it requires win32 to work. Is requiring win32 as a module acceptable?

Feature/Keyboard

Relates to #9

Similarly to hotkeys, keyboard implements pure-python, cross-platform keyboard functionality.

I'm not sure how much value there is in implementing this right now, as anyone should be able to use keyboard and get more than enough functionality.

At any rate, I'm not sure what interface this will take if any, but it's a low priority for now for the reasons mentioned.

Run script by specifying path to an ahk file

Currently, the only way to run arbitrary autohotkey scripts is to use run_script, which only accepts a script as a string of the full script.

Functionality should be added to specify the path of an autohotkey script. Something like this should be possible

ahk.run_script('C:\\Path\\To\\MyScript.ahk')

I think this can safely/reasonably be added to the run_script method without issue.

Changes for AHK_PATH

Per action items out of #31 -- It would probably be nice to see some improvements for how this environment variable is documented/used. I think I want to:

  • update docs to be more clear on how AHK_PATH is used
  • raise an error (or warning?) on mis-configuration of of the variable

Alternatives might include

  • rename the variable
  • have this functionality removed/deprecated
  • add functionality to support either specify a directory or executable file.

Would this awesome lib using AutoHotkey.dll?

dll file can be upload to pypi, and I found an issue while call 64bit AutoHotkey.dll,
will this ahk lib support dll file path arg?

Download URL:
https://github.com/HotKeyIt/ahkdll-v1-release/

python 64-bit: x64w/AutoHotkey.dll or AutoHotkeyMini.dll
python 64-bit: Win32w/AutoHotkey.dll or AutoHotkeyMini.dll

btw, 64-bit dll seems occur an crash while using ahkgetvar

main.py

#! python3
import ctypes
import time
import sys
import pathlib
import typing

dll_file_path = str(
    pathlib.Path(__file__).parent / f'AutoHotkey{sys.hash_info.width}.dll')

ahk_instance = ctypes.cdll.LoadLibrary(dll_file_path)
ahk_instance = ctypes.CDLL(dll_file_path)

ahk_instance.ahktextdll("")

while not ahk_instance.ahkReady():
    time.sleep(0.1)


def goahk(code: str):
    """run source code with autohotkey."""
    return ahk_instance.ahkExec(code)


def getahk(var_name: str):
    """get var value from ahk script by var name"""
    result = ahk_instance.ahkgetvar(var_name, 0)
    result = ctypes.cast(result, ctypes.c_wchar_p)
    return result.value


__all__ = ['goahk', 'getahk']


def test():
    goahk(u'''msgbox Hello World;
var_name=sss
    ''')
    print(getahk('var_name'), flush=1)


if __name__ == "__main__":
    test()

I put the dll file in the dir of main.py
using 32-bit python.exe will run success => show msgbox and print sss
using 32-bit python.exe will run failed=> show msgbox and exited with code=3221225477

sorry for my stupid English grammar...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.