A Python封装的AHK
项目描述
ahk
完全类型的Python封装AutoHotkey。
安装
pip install ahk
需要Python 3.8+
支持AutoHotkey v1和v2。另请参阅: 非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)
示例
本包中可用的一些函数的非穷尽性示例。请参阅 完整文档 以获取完整的API参考和附加功能。
热键
可以将热键配置为运行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
现在每当您按下 + n,将在后台线程中调用
my_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)
还有用于删除热键的方法
# ...
ahk.remove_hotkey('#n') # remove a hotkey by its keyname
ahk.clear_hotkeys() # remove all hotkeys
注意以下内容
- 热键在单独的进程中运行,必须手动启动(使用
ahk.start_hotkeys()
) - 可以使用
ahk.stop_hotkeys()
停止热键(不会停止正在运行的回调函数) - 热字符串(以下讨论)与热键共享相同的进程,并以相同的方式启动/停止
- 如果在进程运行时添加或删除热键或热字符串,则自动重新启动底层的AHK进程
请参阅相关的AHK文档
热字符串
热字符串也可以添加到热键进程线程。
除了热字符串支持正常的AHK字符串替换外,您还可以提供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
您还可以删除热字符串
ahk.remove_hotstring('btw') # remove a hotstring by its trigger sequence
ahk.clear_hotstrings() # remove all registered hotstrings
鼠标
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
键盘
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')
窗口
您也可以对窗口进行操作。
获取窗口
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!')
处理窗口
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)
可以直接调用各种窗口方法,而无需先创建一个 Window
对象。例如,可以使用底层的 win_*
方法在 AHK
类上直接调用,而不是使用上面的 win.close()
,可以调用 ahk.win_close(title='Untitled - Notepad')
。
屏幕
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
数据
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
您也可以获取/设置 ClipboardAll
-- 然而,您不应该尝试使用除恰好由 get_clipboard_all
返回的数据以外的任何数据调用 set_clipboard_all
,否则可能会发生意外问题。
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
您还可以设置一个回调,当剪贴板内容更改时执行。与上面提到的Hotkey方法一样,您也可以设置异常处理程序。与热键一样,on_clipboard_change
回调也要求调用 .start_hotkeys()
才能生效。
回调函数必须接受一个位置参数,该参数是一个整数,表示剪贴板的数据类型。
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
声音
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
工具提示/托盘提示
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
对话框
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')
全局状态更改
您可以更改各种全局状态,如 CoordMode
、DetectHiddenWindows
等,这样您就不必直接将这些参数传递给函数调用。
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
添加指令
您可以将指令添加到所有生成的脚本中。例如,为了防止AHK托盘图标出现,可以添加NoTrayIcon指令。
from ahk import AHK
from ahk.directives import NoTrayIcon
ahk = AHK(directives=[NoTrayIcon])
默认情况下,会自动添加一些指令以确保功能,并将与任何用户提供的指令合并。
默认情况下,指令不应用于处理热键和热字符串的AHK进程(以下讨论)。要使用关键字参数 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)
托盘菜单图标
如上所述,如果您愿意,可以隐藏托盘图标。此外,还有一些可用于自定义托盘图标的方法。
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()
注册表方法
您可以读取/写入/删除注册表键
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')
如果键不存在或发生其他问题,将引发异常。
非阻塞模式
此库中的大多数方法都提供了非阻塞接口,因此您的Python脚本可以在AHK脚本运行的同时继续执行。
默认情况下,所有调用都是 阻塞的 -- 每个函数将在下一个函数运行之前完全执行。
但是,有时您可能希望在AHK执行某些代码时运行其他代码。当提供带有 False
的 blocking
关键字参数时,函数调用将立即返回,而AHK函数将在后台执行。
例如,您可以慢慢移动鼠标,并在其移动时报告其位置
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
当您指定 blocking=False
时,您将始终接收到一个特殊的 FutureResult
对象(或者在异步API中讨论的 AsyncFutureResult
对象),它允许您等待函数完成并通过 get_result
函数检索返回值。即使函数通常返回 None
,这也很有用,以确保AHK已完成函数的执行。
非阻塞调用
- 将在新的AHK进程中隔离,完成调用后终止
- 总是立即启动
- 不会继承之前的全局状态更改(例如,来自
set_coord_mode
调用或类似的)-- 这可能在未来的版本中发生变化。 - 不会阻止其他调用启动
- 将始终返回一个特殊的
FutureResult
对象(或在异步API中讨论的AsyncFutureResult
对象),这允许您等待函数完成并通过result
函数检索返回值。即使函数通常返回None
,这也可以确保AHK已执行函数。
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
异步API(asyncio)
提供了一个异步API,以便可以使用async
/await
调用函数。异步API中提供了与同步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())
异步API与正常API相同,有一些明显的区别
- 虽然属性(如窗口的
.mouse_position
或.title
)可以被await
,但已添加了一些额外的方法(如get_mouse_position()
和get_title()
),以提供更直观的API,并且建议使用这些方法而不是属性。 - 异步API中不允许使用属性设置器(例如,
ahk.mouse_position = (200, 200)
)(将引发RunTimeError)。属性设置器在同步API中仍然可用。 AsyncFutureResult
对象(在指定blocking=False
时返回)与同步API中的FutureResult
对象工作相同,但result
方法不支持timeout
关键字)。
注意以下事项:
- 默认情况下,单个
AsyncAHK
实例上的等待任务不会并发运行。您必须使用blocking=False
,如同步API中所示,或者使用多个AsyncAHK
实例。 - 在异步与同步API中处理热键(及其回调)没有区别。
类型提示和mypy
此库已完全类型提示,允许您利用像mypy
这样的工具来帮助验证代码的类型正确性。实现类型检查功能的IDE也能够利用类型提示来帮助确保代码的安全性。
运行任意AutoHotkey脚本
您还可以以.ahk
脚本文件或包含AHK代码的字符串形式运行任意AutoHotkey代码。
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)
非Python依赖项
要使用此包,您需要AutoHotkey可执行文件(例如,AutoHotkey.exe
)。它默认应位于PATH上或默认安装位置(v1的C:\Program Files\AutoHotkey\AutoHotkey.exe
或v2的C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe
)。
AutoHotkey v1和v2都完全支持,尽管使用哪个版本可能会出现一些行为差异。请参见以下说明。
为v1和v2提供AutoHotkey二进制文件的建议方法是为此包安装binary
额外内容。这将提供必要的可执行文件,并有助于确保它们正确放置在PATH上。
pip install "ahk[binary]"
或者,您可以在代码中提供路径
from ahk import AHK
ahk = AHK(executable_path='C:\\path\\to\\AutoHotkey.exe')
您还可以使用AHK_PATH
环境变量来指定可执行文件的位置。
set AHK_PATH=C:\Path\To\AutoHotkey.exe
python myscript.py
使用AHK v2
默认情况下,如果没有设置executable_path
参数(或AHK_PATH
环境变量),则仅在PATH上或默认安装位置搜索AutoHotkey v1的二进制文件名。此行为可能在未来的版本中更改,以允许默认使用v2。
要使用AutoHotkey版本2,您可以执行以下任何一项操作
- 提供包含AutoHotkey v2二进制文件位置的
executable_path
关键字参数 - 使用包含AutoHotkey v2二进制文件位置的
AHK_PATH
环境变量 - 提供包含值
v2
的version
关键字参数,这将启用使用AutoHotkey v2二进制文件名和默认安装位置查找可执行文件。
例如
from ahk import AHK
ahk = AHK(executable_path=r'C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe')
# OR
ahk = AHK(version='v2')
当您提供version
关键字参数(可以是"v1"
或"v2"
)时,将执行检查以确保提供的(或发现的)二进制文件与请求的版本匹配。当省略version
关键字时,版本将自动从提供的(或发现的)可执行二进制文件中确定。
使用AutoHotkey v1与v2的区别
本项目的API最初是为AutoHotkey v1设计的,即使在使用AutoHotkey v2时,函数签名也相同。虽然大多数行为保持不变,但与v1相比,使用v2时,某些行为会发生改变。这主要是由于两个版本之间的底层差异造成的。
在使用此库与AutoHotkey v2一起使用时,您可能会遇到以下一些显著的差异:
- 查找并返回窗口的函数通常会引发异常,而不是返回
None
(在AutoHotkey v2中,当窗口或控件无法找到时,通常会抛出TargetError) - 当
control
参数未指定时,ControlSend
(ahk.control_send
或Window.send
或Control.send
)在AutoHotkey v2中的行为与v1不同。在v1中,按键发送到最顶层的控件,这通常是正确的行为。在v2中,按键直接发送到窗口。这意味着在许多情况下,使用V2时需要明确指定控件。 - 在v2中不支持某些功能——特别是:对于
TrayTip
(ahk.show_traytip
)的secondstowait
参数已从v2中删除。在Python包装器中指定此参数将发出警告,并且参数将被忽略。 - 在v1中存在但在v2中尚未实现的功能——这预计将在未来的版本中改变。特别是:一些声音函数尚未实现。
- v2中的默认SendMode更改为
Input
,而不是v1中的Event
(例如,作为结果,例如,mouse_move
和mouse_drag
的鼠标速度参数将在V2中忽略,除非更改发送模式) - AutoHotkey v2中的默认TitleMatchMode为
2
。在AutoHotkey v1中为1
。使用title_match_mode
关键字参数到win_get
和其他接受此关键字参数的方法来控制此行为,或者使用set_title_match_mode
来更改默认行为(非阻塞调用在单独的进程中运行,不受set_title_match_mode
的影响)
扩展:添加您的自己的AutoHotkey代码(测试版)
您可以为扩展ahk
的功能开发扩展——即:编写自己的AutoHotkey代码,并为AHK类添加额外的函数。有关更多信息,请参阅扩展文档。
贡献
所有贡献都受到欢迎并受到赞赏。
请随时为反馈、想法、功能请求或问题打开GitHub问题或PR。
类似的项目
以下是一些常用的自动化Python的项目。
项目详情
下载文件
下载适合您平台的应用程序文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源分发
构建分发
ahk-1.8.0.tar.gz的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 0fbd2dc71566d60d13326238347109f591119a1338a35baa6a473c5c3d7ec20c |
|
MD5 | d482aca35df90884fd5e2e2d8dcc956b |
|
BLAKE2b-256 | d23c5f35154c5f90197657335f2066c232411ba8334e1d780dbb0783e3b3dd89 |
ahk-1.8.0-py3-none-any.whl的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 0947b09d35b1d43c6c7da6bd6fb90acd05b7ab2e7bc918c8238e0533495ef74e |
|
MD5 | faf46b12bf3f8a8f7768bfecdebeac59 |
|
BLAKE2b-256 | 877f1ed8df77c1fe54f0a9d3c9df60c547b8a646490d1730b7494efce6e6f9f4 |