Source code for ahkpy.settings

import contextvars
import dataclasses as dc

from .flow import ahk_call

__all__ = [
    "Settings",
    "default_settings",
    "get_settings",
    "local_settings",
    "set_settings",
]


_current_settings = contextvars.ContextVar("script_settings")


[docs]@dc.dataclass class Settings: """Settings() .. ^^ Hide the __init__ args from the docs. The object that holds thread-local AutoHotkey settings. All delays and durations are in seconds. """ #: The delay after each control-modifying method: :meth:`~Control.check`, #: :meth:`~Control.uncheck`, :meth:`~window.BaseWindow.enable`, #: :meth:`~window.BaseWindow.disable`, :meth:`~window.BaseWindow.hide`, #: :meth:`~window.BaseWindow.show`, :meth:`~Control.focus`, #: :meth:`~Control.paste`, :meth:`~Control.choose_item_index`, #: :meth:`~Control.choose_item`, :meth:`~window.BaseWindow.move`, and the #: :attr:`~Control.text`, :attr:`~Control.is_checked`, #: :attr:`~Control.list_choice_index`, #: :attr:`~window.BaseWindow.is_enabled`, #: :attr:`~window.BaseWindow.is_visible`, #: :attr:`~window.BaseWindow.rect`, #: :attr:`~window.BaseWindow.position`, :attr:`~window.BaseWindow.size`, #: :attr:`~window.BaseWindow.x`, :attr:`~window.BaseWindow.y`, #: :attr:`~window.BaseWindow.width`, :attr:`~window.BaseWindow.height` #: setters. #: #: :command: `SetControlDelay #: <https://www.autohotkey.com/docs/commands/SetControlDelay.htm>`_ control_delay: float = 0.02 #: The delay after each keystroke sent by #: :func:`~ahkpy.send_event` and :meth:`window.BaseWindow.send`. #: #: :command: `SetKeyDelay #: <https://www.autohotkey.com/docs/commands/SetKeyDelay.htm>`_ key_delay: float = 0.01 #: The delay after the press of the key and before its release sent by #: :func:`~ahkpy.send_event` and :meth:`window.BaseWindow.send`. #: #: :command: `SetKeyDelay #: <https://www.autohotkey.com/docs/commands/SetKeyDelay.htm>`_ key_duration: float = -1 #: The delay after each keystroke sent by #: :func:`~ahkpy.send_play`. #: #: :command: `SetKeyDelay #: <https://www.autohotkey.com/docs/commands/SetKeyDelay.htm>`_ key_delay_play: float = -1 #: The delay after the press of the key and before its release sent by #: :func:`~ahkpy.send_play`. #: #: :command: `SetKeyDelay #: <https://www.autohotkey.com/docs/commands/SetKeyDelay.htm>`_ key_duration_play: float = -1 #: The delay after each mouse movement or click in the Event mode. #: #: :command: `SetMouseDelay #: <https://www.autohotkey.com/docs/commands/SetMouseDelay.htm>`_ mouse_delay: float = 0.01 #: The delay after each mouse movement or click in the Play mode. #: #: :command: `SetMouseDelay #: <https://www.autohotkey.com/docs/commands/SetMouseDelay.htm>`_ mouse_delay_play: float = -1 #: The speed of mouse movement in the range 0 (fastest) to 100 (slowest). #: Affects only the Event mode. #: #: :command: `SetDefaultMouseSpeed #: <https://www.autohotkey.com/docs/commands/SetDefaultMouseSpeed.htm>`_ mouse_speed: int = 2 #: Controls which artificial keyboard and mouse events are ignored by #: hotkeys and hotstrings. Must be an integer between 0 and 100. #: #: :command: `SendLevel #: <https://www.autohotkey.com/docs/commands/SendLevel.htm>`_ send_level: int = 0 #: The default mode for :func:`~ahkpy.send` and mouse functions. #: #: :command: `SendMode #: <https://www.autohotkey.com/docs/commands/SendMode.htm>`_ send_mode: str = "input" #: The delay after each window-modifying method. It affects the following: #: #: - :class:`Windows` methods: :meth:`~Windows.close_all`, #: :meth:`~Windows.hide_all`, :meth:`~Windows.kill_all`, #: :meth:`~Windows.maximize_all`, :meth:`~Windows.minimize_all`, #: :meth:`~Windows.restore_all`, :meth:`~Windows.show_all` #: - :class:`Window` methods: :meth:`~Window.minimize`, #: :meth:`~Window.restore`, :meth:`~Window.maximize`, #: :meth:`~window.BaseWindow.hide`, :meth:`~window.BaseWindow.show`, #: :meth:`~Window.close`, :meth:`~Window.kill`, #: :meth:`~window.BaseWindow.move` #: - :class:`Window` setters: :attr:`~Window.is_maximized`, #: :attr:`~Window.is_minimized`, :attr:`~window.BaseWindow.is_enabled`, #: :attr:`~window.BaseWindow.is_visible`, :attr:`~window.BaseWindow.rect`, #: :attr:`~window.BaseWindow.position`, :attr:`~window.BaseWindow.size`, #: :attr:`~window.BaseWindow.x`, :attr:`~window.BaseWindow.y`, #: :attr:`~window.BaseWindow.width`, :attr:`~window.BaseWindow.height` #: #: :command: `SetWinDelay #: <https://www.autohotkey.com/docs/commands/SetWinDelay.htm>`_ win_delay: float = 0.1 # Should CoordMode also be here? I don't think so because the above settings # change only some aspects like speed and delay and don't change the overall # behavior. For example, the function that moves the mouse cursor or types a # word is expected to mostly do the same regardless of these settings. # # CoordMode on the other hand completely changes the behavior of the # affected functions. def copy(self): return dc.replace(self) def __delattr__(self, name): raise AttributeError(f"{name} cannot be deleted")
[docs]def get_settings() -> Settings: """get_settings() -> ahkpy.Settings Return the current settings for the active thread. """ try: return _current_settings.get() except LookupError: settings = default_settings.copy() _current_settings.set(settings) return settings
[docs]def set_settings(settings): """Set the current settings for the active thread.""" _current_settings.set(settings)
[docs]def local_settings(settings=None): """local_settings(settings=None) Return a context manager that will set the current settings for the active thread to a copy of *settings* on entry to the with-statement and restore the previous settings when exiting the with-statement. If no context is specified, a copy of the current settings is used. For example, the following code removes the current delay between window manipulations, modifies the active window, and then automatically restores the previous settings:: prev_delay = ahkpy.get_settings().win_delay with ahkpy.local_settings() as settings: settings.win_delay = 0 win = ahkpy.windows.get_active() win.maximize() win.restore() assert ahkpy.get_settings().win_delay == prev_delay The function can also be used to safely change the settings of an AHK callback without affecting the settings in other functions:: @ahkpy.hotkey("F1") def isolated_settings(): settings = ahkpy.local_settings().activate() settings.win_delay = 0 ... """ if settings is None: settings = get_settings() return _SettingsManager(settings)
class _SettingsManager: """Context manager class to support local_settings(). Sets a copy of the supplied context in __enter__() and restores the previous settings in __exit__(). """ def __init__(self, new_settings): self.new_settings = new_settings.copy() def activate(self) -> Settings: self.prior_settings = get_settings() set_settings(self.new_settings) return self.new_settings __enter__ = activate def __exit__(self, t, v, tb): set_settings(self.prior_settings) default_settings = Settings() set_settings(default_settings) def optional_ms(value): if value is None or value < 0: return -1 else: return int(value * 1000) COORD_TARGETS = {"tooltip", "pixel", "mouse", "caret", "menu"} COORD_MODES = {"screen", "window", "client"} def _set_coord_mode(target, relative_to): if target not in COORD_TARGETS: raise ValueError(f"{target!r} is not a valid coord target") if relative_to not in COORD_MODES: raise ValueError(f"{relative_to!r} is not a valid coord mode") ahk_call("CoordMode", target, relative_to)