From dbcc090f56c71d08e9395b300a8d3156c1857553 Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Tue, 22 Aug 2023 15:37:41 -0700 Subject: [PATCH 1/9] initial work to enable extensions --- ahk/_async/engine.py | 36 +++++++++++- ahk/_async/transport.py | 7 ++- ahk/_constants.py | 14 +++++ ahk/_sync/engine.py | 35 +++++++++++- ahk/_sync/transport.py | 5 +- ahk/_sync/window.py | 12 +--- ahk/extensions.py | 99 +++++++++++++++++++++++++++++++++ ahk/templates/daemon.ahk | 14 +++++ tests/_async/test_extensions.py | 67 ++++++++++++++++++++++ tests/_sync/test_extensions.py | 66 ++++++++++++++++++++++ 10 files changed, 342 insertions(+), 13 deletions(-) create mode 100644 ahk/extensions.py create mode 100644 tests/_async/test_extensions.py create mode 100644 tests/_sync/test_extensions.py diff --git a/ahk/_async/engine.py b/ahk/_async/engine.py index c0a6d8b..8804426 100644 --- a/ahk/_async/engine.py +++ b/ahk/_async/engine.py @@ -6,6 +6,7 @@ import tempfile import time import warnings +from functools import partial from typing import Any from typing import Awaitable from typing import Callable @@ -34,6 +35,7 @@ else: from typing import TypeAlias +from ..extensions import Extension, _extension_method_registry, _ExtensionMethodRegistry from ..keys import Key from .transport import AsyncDaemonProcessTransport from .transport import AsyncFutureResult @@ -135,13 +137,45 @@ def __init__( TransportClass: Optional[Type[AsyncTransport]] = None, directives: Optional[list[Directive | Type[Directive]]] = None, executable_path: str = '', + extensions: list[Extension] | None | Literal['auto'] = None, ): + self._extension_registry: _ExtensionMethodRegistry + self._extensions: list[Extension] + if extensions == 'auto': + is_async = False + is_async = True # unasync: remove + if is_async: + extensions = [entry.extension for name, entry in _extension_method_registry.async_methods.items()] + else: + extensions = [entry.extension for name, entry in _extension_method_registry.sync_methods.items()] + self._extension_registry = _extension_method_registry + self._extensions = extensions + else: + self._extensions = extensions or [] + self._extension_registry = _ExtensionMethodRegistry(sync_methods={}, async_methods={}) + for ext in self._extensions: + self._extension_registry.merge(ext._extension_method_registry) + if TransportClass is None: TransportClass = AsyncDaemonProcessTransport assert TransportClass is not None - transport = TransportClass(executable_path=executable_path, directives=directives) + transport = TransportClass(executable_path=executable_path, directives=directives, extensions=extensions) self._transport: AsyncTransport = transport + def __getattr__(self, name: str) -> Callable[..., Any]: + is_async = False + is_async = True # unasync: remove + if is_async: + if name in self._extension_registry.async_methods: + method = self._extension_registry.async_methods[name].method + return partial(method, self) + else: + if name in self._extension_registry.sync_methods: + method = self._extension_registry.sync_methods[name].method + return partial(method, self) + + raise AttributeError(f'{self.__class__.__name__!r} object has no attribute {name!r}') + def add_hotkey( self, keyname: str, callback: Callable[[], Any], ex_handler: Optional[Callable[[str, Exception], Any]] = None ) -> None: diff --git a/ahk/_async/transport.py b/ahk/_async/transport.py index d34f18b..46c4b97 100644 --- a/ahk/_async/transport.py +++ b/ahk/_async/transport.py @@ -38,6 +38,7 @@ import jinja2 +from ahk.extensions import Extension from ahk._hotkey import ThreadedHotkeyTransport, Hotkey, Hotstring from ahk.message import RequestMessage from ahk.message import ResponseMessage @@ -656,7 +657,9 @@ def __init__( directives: Optional[list[Directive | Type[Directive]]] = None, jinja_loader: Optional[jinja2.BaseLoader] = None, template: Optional[jinja2.Template] = None, + extensions: list[Extension] | None = None, ): + self._extensions = extensions or [] self._proc: Optional[AsyncAHKProcess] self._proc = None self._temp_script: Optional[str] = None @@ -711,7 +714,9 @@ def _render_script(self, template: Optional[jinja2.Template] = None, **kwargs: A template = self._template kwargs['daemon'] = self.__template message_types = {str(tom, 'utf-8'): c.__name__.upper() for tom, c in _message_registry.items()} - return template.render(directives=self._directives, message_types=message_types, **kwargs) + return template.render( + directives=self._directives, message_types=message_types, extensions=self._extensions, **kwargs + ) @property def lock(self) -> Any: diff --git a/ahk/_constants.py b/ahk/_constants.py index f2aacd0..bf624f0 100644 --- a/ahk/_constants.py +++ b/ahk/_constants.py @@ -6,7 +6,16 @@ #NoEnv #Persistent #SingleInstance Off +{% block extension_directives %} +; BEGIN extension includes +{% for ext in extensions %} +{% for inc in ext.includes %} +{{ inc }} +{% endfor %} +{% endfor %} +; END extension includes +{% endblock extension_directives %} ; BEGIN user-defined directives {% block user_directives %} {% for directive in directives %} @@ -2833,7 +2842,12 @@ return decoded_commands } +; BEGIN extension scripts +{% for ext in extensions %} +{{ ext.script_text }} +{% endfor %} +; END extension scripts {% block before_autoexecute %} {% endblock before_autoexecute %} diff --git a/ahk/_sync/engine.py b/ahk/_sync/engine.py index faf7853..b9dfc19 100644 --- a/ahk/_sync/engine.py +++ b/ahk/_sync/engine.py @@ -6,6 +6,7 @@ import tempfile import time import warnings +from functools import partial from typing import Any from typing import Awaitable from typing import Callable @@ -34,6 +35,7 @@ else: from typing import TypeAlias +from ..extensions import Extension, _extension_method_registry, _ExtensionMethodRegistry from ..keys import Key from .transport import DaemonProcessTransport from .transport import FutureResult @@ -131,13 +133,44 @@ def __init__( TransportClass: Optional[Type[Transport]] = None, directives: Optional[list[Directive | Type[Directive]]] = None, executable_path: str = '', + extensions: list[Extension] | None | Literal['auto'] = None ): + self._extension_registry: _ExtensionMethodRegistry + self._extensions: list[Extension] + if extensions == 'auto': + is_async = False + if is_async: + extensions = [entry.extension for name, entry in _extension_method_registry.async_methods.items()] + else: + extensions = [entry.extension for name, entry in _extension_method_registry.sync_methods.items()] + self._extension_registry = _extension_method_registry + self._extensions = extensions + else: + self._extensions = extensions or [] + self._extension_registry = _ExtensionMethodRegistry(sync_methods={}, async_methods={}) + for ext in self._extensions: + self._extension_registry.merge(ext._extension_method_registry) + + if TransportClass is None: TransportClass = DaemonProcessTransport assert TransportClass is not None - transport = TransportClass(executable_path=executable_path, directives=directives) + transport = TransportClass(executable_path=executable_path, directives=directives, extensions=extensions) self._transport: Transport = transport + def __getattr__(self, name: str) -> Callable[..., Any]: + is_async = False + if is_async: + if name in self._extension_registry.async_methods: + method = self._extension_registry.async_methods[name].method + return partial(method, self) + else: + if name in self._extension_registry.sync_methods: + method = self._extension_registry.sync_methods[name].method + return partial(method, self) + + raise AttributeError(f'{self.__class__.__name__!r} object has no attribute {name!r}') + def add_hotkey( self, keyname: str, callback: Callable[[], Any], ex_handler: Optional[Callable[[str, Exception], Any]] = None ) -> None: diff --git a/ahk/_sync/transport.py b/ahk/_sync/transport.py index 0c964f8..11ccb00 100644 --- a/ahk/_sync/transport.py +++ b/ahk/_sync/transport.py @@ -38,6 +38,7 @@ import jinja2 +from ahk.extensions import Extension from ahk._hotkey import ThreadedHotkeyTransport, Hotkey, Hotstring from ahk.message import RequestMessage from ahk.message import ResponseMessage @@ -630,7 +631,9 @@ def __init__( directives: Optional[list[Directive | Type[Directive]]] = None, jinja_loader: Optional[jinja2.BaseLoader] = None, template: Optional[jinja2.Template] = None, + extensions: list[Extension] | None = None ): + self._extensions = extensions or [] self._proc: Optional[SyncAHKProcess] self._proc = None self._temp_script: Optional[str] = None @@ -684,7 +687,7 @@ def _render_script(self, template: Optional[jinja2.Template] = None, **kwargs: A template = self._template kwargs['daemon'] = self.__template message_types = {str(tom, 'utf-8'): c.__name__.upper() for tom, c in _message_registry.items()} - return template.render(directives=self._directives, message_types=message_types, **kwargs) + return template.render(directives=self._directives, message_types=message_types, extensions=self._extensions, **kwargs) @property def lock(self) -> Any: diff --git a/ahk/_sync/window.py b/ahk/_sync/window.py index 8701e48..30d0a8b 100644 --- a/ahk/_sync/window.py +++ b/ahk/_sync/window.py @@ -61,15 +61,11 @@ def __hash__(self) -> int: return hash(self._ahk_id) def close(self) -> None: - self._engine.win_close( - title=f'ahk_id {self._ahk_id}', detect_hidden_windows=True, title_match_mode=(1, 'Fast') - ) + self._engine.win_close(title=f'ahk_id {self._ahk_id}', detect_hidden_windows=True, title_match_mode=(1, 'Fast')) return None def kill(self) -> None: - self._engine.win_kill( - title=f'ahk_id {self._ahk_id}', detect_hidden_windows=True, title_match_mode=(1, 'Fast') - ) + self._engine.win_kill(title=f'ahk_id {self._ahk_id}', detect_hidden_windows=True, title_match_mode=(1, 'Fast')) def exists(self) -> bool: return self._engine.win_exists( @@ -591,9 +587,7 @@ def set_transparent( blocking=blocking, ) - def set_trans_color( - self, color: Union[int, str], *, blocking: bool = True - ) -> Union[None, FutureResult[None]]: + def set_trans_color(self, color: Union[int, str], *, blocking: bool = True) -> Union[None, FutureResult[None]]: return self._engine.win_set_trans_color( color=color, title=f'ahk_id {self._ahk_id}', diff --git a/ahk/extensions.py b/ahk/extensions.py new file mode 100644 index 0000000..7d58233 --- /dev/null +++ b/ahk/extensions.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +import asyncio +import warnings +from dataclasses import dataclass +from typing import Any +from typing import Callable +from typing import ParamSpec +from typing import TypeVar + +from .directives import Include + + +@dataclass +class _ExtensionEntry: + extension: Extension + method: Callable[..., Any] + + +@dataclass +class _ExtensionMethodRegistry: + sync_methods: dict[str, _ExtensionEntry] + async_methods: dict[str, _ExtensionEntry] + + def register(self, ext: Extension, f: Callable[P, T]) -> Callable[P, T]: + if asyncio.iscoroutinefunction(f): + if f.__name__ in self.async_methods: + warnings.warn( + f'Method of name {f.__name__!r} has already been registered. ' + f'Previously registered method {self.async_methods[f.__name__].method!r} ' + f'will be overridden by {f!r}' + ) + self.async_methods[f.__name__] = _ExtensionEntry(extension=ext, method=f) + else: + if f.__name__ in self.sync_methods: + warnings.warn( + f'Method of name {f.__name__!r} has already been registered. ' + f'Previously registered method {self.sync_methods[f.__name__].method!r} ' + f'will be overridden by {f!r}' + ) + self.sync_methods[f.__name__] = _ExtensionEntry(extension=ext, method=f) + return f + + def merge(self, other: _ExtensionMethodRegistry) -> None: + for fname, entry in other.async_methods.items(): + async_method = entry.method + if async_method.__name__ in self.async_methods: + warnings.warn( + f'Method of name {async_method.__name__!r} has already been registered. ' + f'Previously registered method {self.async_methods[async_method.__name__].method!r} ' + f'will be overridden by {async_method!r}' + ) + self.async_methods[async_method.__name__] = entry + for fname, entry in other.sync_methods.items(): + method = entry.method + if method.__name__ in self.sync_methods: + warnings.warn( + f'Method of name {method.__name__!r} has already been registered. ' + f'Previously registered method {self.sync_methods[method.__name__].method!r} ' + f'will be overridden by {method!r}' + ) + self.sync_methods[method.__name__] = entry + + +_extension_method_registry = _ExtensionMethodRegistry(sync_methods={}, async_methods={}) + + +T = TypeVar('T') +P = ParamSpec('P') + + +class Extension: + def __init__( + self, + includes: list[str] | None = None, + script_text: str | None = None, + # template: str | Template | None = None + ): + self._text: str = script_text or '' + # self._template: str | Template | None = template + self._includes: list[str] = includes or [] + self._extension_method_registry = _ExtensionMethodRegistry(sync_methods={}, async_methods={}) + + @property + def script_text(self) -> str: + return self._text + + @script_text.setter + def script_text(self, new_script: str) -> None: + self._text = new_script + + @property + def includes(self) -> list[Include]: + return [Include(inc) for inc in self._includes] + + def register(self, f: Callable[P, T]) -> Callable[P, T]: + self._extension_method_registry.register(self, f) + _extension_method_registry.register(self, f) + return f diff --git a/ahk/templates/daemon.ahk b/ahk/templates/daemon.ahk index fead619..22b7ab8 100644 --- a/ahk/templates/daemon.ahk +++ b/ahk/templates/daemon.ahk @@ -3,7 +3,16 @@ #NoEnv #Persistent #SingleInstance Off +{% block extension_directives %} +; BEGIN extension includes +{% for ext in extensions %} +{% for inc in ext.includes %} +{{ inc }} +{% endfor %} +{% endfor %} +; END extension includes +{% endblock extension_directives %} ; BEGIN user-defined directives {% block user_directives %} {% for directive in directives %} @@ -2830,7 +2839,12 @@ CommandArrayFromQuery(ByRef text) { return decoded_commands } +; BEGIN extension scripts +{% for ext in extensions %} +{{ ext.script_text }} +{% endfor %} +; END extension scripts {% block before_autoexecute %} {% endblock before_autoexecute %} diff --git a/tests/_async/test_extensions.py b/tests/_async/test_extensions.py new file mode 100644 index 0000000..95651dc --- /dev/null +++ b/tests/_async/test_extensions.py @@ -0,0 +1,67 @@ +import asyncio +import time +import unittest + +import pytest + +from ahk import AsyncAHK +from ahk.extensions import Extension + +async_sleep = asyncio.sleep # unasync: remove + +sleep = time.sleep + +ext_text = '''\ +AHKDoSomething(ByRef command) { + global STRINGRESPONSEMESSAGE + arg := command[2] + return FormatResponse(STRINGRESPONSEMESSAGE, Format("test{}", arg)) +} +''' + +async_extension = Extension(script_text=ext_text) + + +@async_extension.register +async def do_something(ahk, arg: str) -> str: + res = await ahk._transport.function_call('AHKDoSomething', [arg]) + return res + + +class TestExtensions(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + self.ahk = AsyncAHK(extensions=[async_extension]) + + async def asyncTearDown(self) -> None: + self.ahk._transport._proc.kill() + time.sleep(0.2) + + async def test_ext(self): + res = await self.ahk.do_something('foo') + assert res == 'testfoo' + + +class TestExtensionsAuto(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + self.ahk = AsyncAHK(extensions='auto') + + async def asyncTearDown(self) -> None: + self.ahk._transport._proc.kill() + time.sleep(0.2) + + async def test_ext(self): + res = await self.ahk.do_something('foo') + assert res == 'testfoo' + + +class TestNoExtensions(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + self.ahk = AsyncAHK() + await self.ahk.get_mouse_position() # cause daemon to start + + async def asyncTearDown(self) -> None: + self.ahk._transport._proc.kill() + time.sleep(0.2) + + async def test_ext(self): + assert not hasattr(self.ahk, 'do_something') diff --git a/tests/_sync/test_extensions.py b/tests/_sync/test_extensions.py new file mode 100644 index 0000000..c78d392 --- /dev/null +++ b/tests/_sync/test_extensions.py @@ -0,0 +1,66 @@ +import asyncio +import time +import unittest + +import pytest + +from ahk import AHK +from ahk.extensions import Extension + + +sleep = time.sleep + +ext_text = '''\ +AHKDoSomething(ByRef command) { + global STRINGRESPONSEMESSAGE + arg := command[2] + return FormatResponse(STRINGRESPONSEMESSAGE, Format("test{}", arg)) +} +''' + +async_extension = Extension(script_text=ext_text) + + +@async_extension.register +def do_something(ahk, arg: str) -> str: + res = ahk._transport.function_call('AHKDoSomething', [arg]) + return res + + +class TestExtensions(unittest.TestCase): + def setUp(self) -> None: + self.ahk = AHK(extensions=[async_extension]) + + def tearDown(self) -> None: + self.ahk._transport._proc.kill() + time.sleep(0.2) + + def test_ext(self): + res = self.ahk.do_something('foo') + assert res == 'testfoo' + + +class TestExtensionsAuto(unittest.TestCase): + def setUp(self) -> None: + self.ahk = AHK(extensions='auto') + + def tearDown(self) -> None: + self.ahk._transport._proc.kill() + time.sleep(0.2) + + def test_ext(self): + res = self.ahk.do_something('foo') + assert res == 'testfoo' + + +class TestNoExtensions(unittest.TestCase): + def setUp(self) -> None: + self.ahk = AHK() + self.ahk.get_mouse_position() # cause daemon to start + + def tearDown(self) -> None: + self.ahk._transport._proc.kill() + time.sleep(0.2) + + def test_ext(self): + assert not hasattr(self.ahk, 'do_something') From 06a38f8a5c51826bce07ce9b39b1f2da028e6201 Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Tue, 22 Aug 2023 17:32:12 -0700 Subject: [PATCH 2/9] fix typing import for python<3.10 --- ahk/extensions.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ahk/extensions.py b/ahk/extensions.py index 7d58233..af3deec 100644 --- a/ahk/extensions.py +++ b/ahk/extensions.py @@ -1,13 +1,18 @@ from __future__ import annotations import asyncio +import sys import warnings from dataclasses import dataclass from typing import Any from typing import Callable -from typing import ParamSpec from typing import TypeVar +if sys.version_info < (3, 10): + from typing_extensions import ParamSpec +else: + from typing import ParamSpec + from .directives import Include @@ -17,6 +22,10 @@ class _ExtensionEntry: method: Callable[..., Any] +T = TypeVar('T') +P = ParamSpec('P') + + @dataclass class _ExtensionMethodRegistry: sync_methods: dict[str, _ExtensionEntry] @@ -65,10 +74,6 @@ def merge(self, other: _ExtensionMethodRegistry) -> None: _extension_method_registry = _ExtensionMethodRegistry(sync_methods={}, async_methods={}) -T = TypeVar('T') -P = ParamSpec('P') - - class Extension: def __init__( self, From 47c3b64eb70f42eaa89e4a85e620dc0c7f06a523 Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Tue, 22 Aug 2023 18:49:26 -0700 Subject: [PATCH 3/9] prevent merging duplicate methods --- ahk/_async/engine.py | 8 ++++++-- ahk/_sync/engine.py | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ahk/_async/engine.py b/ahk/_async/engine.py index 8804426..38874f8 100644 --- a/ahk/_async/engine.py +++ b/ahk/_async/engine.py @@ -145,9 +145,13 @@ def __init__( is_async = False is_async = True # unasync: remove if is_async: - extensions = [entry.extension for name, entry in _extension_method_registry.async_methods.items()] + extensions = list( + set(entry.extension for name, entry in _extension_method_registry.async_methods.items()) + ) else: - extensions = [entry.extension for name, entry in _extension_method_registry.sync_methods.items()] + extensions = list( + set(entry.extension for name, entry in _extension_method_registry.sync_methods.items()) + ) self._extension_registry = _extension_method_registry self._extensions = extensions else: diff --git a/ahk/_sync/engine.py b/ahk/_sync/engine.py index b9dfc19..0a2c6a8 100644 --- a/ahk/_sync/engine.py +++ b/ahk/_sync/engine.py @@ -133,16 +133,16 @@ def __init__( TransportClass: Optional[Type[Transport]] = None, directives: Optional[list[Directive | Type[Directive]]] = None, executable_path: str = '', - extensions: list[Extension] | None | Literal['auto'] = None + extensions: list[Extension] | None | Literal['auto'] = None, ): self._extension_registry: _ExtensionMethodRegistry self._extensions: list[Extension] if extensions == 'auto': is_async = False if is_async: - extensions = [entry.extension for name, entry in _extension_method_registry.async_methods.items()] + extensions = list(set(entry.extension for name, entry in _extension_method_registry.async_methods.items())) else: - extensions = [entry.extension for name, entry in _extension_method_registry.sync_methods.items()] + extensions = list(set(entry.extension for name, entry in _extension_method_registry.sync_methods.items())) self._extension_registry = _extension_method_registry self._extensions = extensions else: @@ -151,7 +151,6 @@ def __init__( for ext in self._extensions: self._extension_registry.merge(ext._extension_method_registry) - if TransportClass is None: TransportClass = DaemonProcessTransport assert TransportClass is not None From 8e38afaf1a5d26eb8ee0e8b699e0e65924611f43 Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Tue, 22 Aug 2023 19:16:23 -0700 Subject: [PATCH 4/9] cleanup --- ahk/_async/engine.py | 10 ++++------ ahk/_sync/engine.py | 6 ++++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ahk/_async/engine.py b/ahk/_async/engine.py index 38874f8..c7937d3 100644 --- a/ahk/_async/engine.py +++ b/ahk/_async/engine.py @@ -145,13 +145,11 @@ def __init__( is_async = False is_async = True # unasync: remove if is_async: - extensions = list( - set(entry.extension for name, entry in _extension_method_registry.async_methods.items()) - ) + methods = _extension_method_registry.async_methods else: - extensions = list( - set(entry.extension for name, entry in _extension_method_registry.sync_methods.items()) - ) + methods = _extension_method_registry.sync_methods + extensions = list(set(entry.extension for name, entry in methods.items())) + self._extension_registry = _extension_method_registry self._extensions = extensions else: diff --git a/ahk/_sync/engine.py b/ahk/_sync/engine.py index 0a2c6a8..8f93d06 100644 --- a/ahk/_sync/engine.py +++ b/ahk/_sync/engine.py @@ -140,9 +140,11 @@ def __init__( if extensions == 'auto': is_async = False if is_async: - extensions = list(set(entry.extension for name, entry in _extension_method_registry.async_methods.items())) + methods = _extension_method_registry.async_methods else: - extensions = list(set(entry.extension for name, entry in _extension_method_registry.sync_methods.items())) + methods = _extension_method_registry.sync_methods + extensions = list(set(entry.extension for name, entry in methods.items())) + self._extension_registry = _extension_method_registry self._extensions = extensions else: From 71cb07b718390ebc35af4a22c30357603c076e58 Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Thu, 24 Aug 2023 18:59:31 -0700 Subject: [PATCH 5/9] new message identification --- ahk/_async/transport.py | 6 +- ahk/_constants.py | 392 +++++++++++++++------------------------ ahk/_sync/transport.py | 10 +- ahk/message.py | 34 +--- ahk/templates/daemon.ahk | 392 +++++++++++++++------------------------ 5 files changed, 320 insertions(+), 514 deletions(-) diff --git a/ahk/_async/transport.py b/ahk/_async/transport.py index 46c4b97..96277d3 100644 --- a/ahk/_async/transport.py +++ b/ahk/_async/transport.py @@ -715,7 +715,11 @@ def _render_script(self, template: Optional[jinja2.Template] = None, **kwargs: A kwargs['daemon'] = self.__template message_types = {str(tom, 'utf-8'): c.__name__.upper() for tom, c in _message_registry.items()} return template.render( - directives=self._directives, message_types=message_types, extensions=self._extensions, **kwargs + directives=self._directives, + message_types=message_types, + message_registry=_message_registry, + extensions=self._extensions, + **kwargs, ) @property diff --git a/ahk/_constants.py b/ahk/_constants.py index bf624f0..39b84fc 100644 --- a/ahk/_constants.py +++ b/ahk/_constants.py @@ -28,30 +28,26 @@ {% endblock directives %} {% block message_types %} -{% for tom, name in message_types.items() %} -{{ name }} := "{{ tom }}" -{% endfor %} +MESSAGE_TYPES := Object({% for tom, msg_class in message_registry.items() %}"{{ msg_class.fqn() }}", "{{ tom.decode('utf-8') }}"{% if not loop.last %}, {% endif %}{% endfor %}) {% endblock message_types %} - NOVALUE_SENTINEL := Chr(57344) FormatResponse(ByRef MessageType, ByRef payload) { + global MESSAGE_TYPES newline_count := CountNewlines(payload) - response := Format("{}`n{}`n{}`n", MessageType, newline_count, payload) + response := Format("{}`n{}`n{}`n", MESSAGE_TYPES[MessageType], newline_count, payload) return response } FormatNoValueResponse() { global NOVALUE_SENTINEL - global NOVALUERESPONSEMESSAGE - return FormatResponse(NOVALUERESPONSEMESSAGE, NOVALUE_SENTINEL) + return FormatResponse("ahk.message.NoValueResponseMessage", NOVALUE_SENTINEL) } FormatBinaryResponse(ByRef bin) { - global B64BINARYRESPONSEMESSAGE b64 := b64encode(bin) - return FormatResponse(B64BINARYRESPONSEMESSAGE, b64) + return FormatResponse("ahk.message.B64BinaryResponseMessage", b64) } AHKSetDetectHiddenWindows(ByRef command) { @@ -78,15 +74,15 @@ AHKGetTitleMatchMode(ByRef command) { {% block AHKGetTitleMatchMode %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, A_TitleMatchMode) + + return FormatResponse("ahk.message.StringResponseMessage", A_TitleMatchMode) {% endblock AHKGetTitleMatchMode %} } AHKGetTitleMatchSpeed(ByRef command) { {% block AHKGetTitleMatchSpeed %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, A_TitleMatchModeSpeed) + + return FormatResponse("ahk.message.StringResponseMessage", A_TitleMatchModeSpeed) {% endblock AHKGetTitleMatchSpeed %} } @@ -100,14 +96,14 @@ AHKGetSendLevel(ByRef command) { {% block AHKGetSendLevel %} - global INTEGERRESPONSEMESSAGE - return FormatResponse(INTEGERRESPONSEMESSAGE, A_SendLevel) + + return FormatResponse("ahk.message.IntegerResponseMessage", A_SendLevel) {% endblock AHKGetSendLevel %} } AHKWinExist(ByRef command) { {% block AHKWinExist %} - global BOOLEANRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -132,9 +128,9 @@ } if WinExist(title, text, extitle, extext) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } DetectHiddenWindows, %current_detect_hw% @@ -170,14 +166,12 @@ DetectHiddenWindows, %detect_hw% } - WinClose, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% - return FormatNoValueResponse() {% endblock AHKWinClose %} } @@ -207,7 +201,6 @@ DetectHiddenWindows, %detect_hw% } - WinKill, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -220,8 +213,6 @@ AHKWinWait(ByRef command) { {% block AHKWinWait %} - global WINDOWRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -250,10 +241,10 @@ WinWait, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { WinGet, output, ID - resp := FormatResponse(WINDOWRESPONSEMESSAGE, output) + resp := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -264,11 +255,8 @@ {% endblock AHKWinWait %} } - AHKWinWaitActive(ByRef command) { {% block AHKWinWaitActive %} - global WINDOWRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -297,10 +285,10 @@ WinWaitActive, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { WinGet, output, ID - resp := FormatResponse(WINDOWRESPONSEMESSAGE, output) + resp := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -311,11 +299,8 @@ {% endblock AHKWinWaitActive %} } - AHKWinWaitNotActive(ByRef command) { {% block AHKWinWaitNotActive %} - global WINDOWRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -344,10 +329,10 @@ WinWaitNotActive, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { WinGet, output, ID - resp := FormatResponse(WINDOWRESPONSEMESSAGE, output) + resp := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -360,7 +345,6 @@ AHKWinWaitClose(ByRef command) { {% block AHKWinWaitClose %} - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -389,7 +373,7 @@ WinWaitClose, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { resp := FormatNoValueResponse() } @@ -412,7 +396,6 @@ match_mode := command[7] match_speed := command[8] - current_match_mode := Format("{}", A_TitleMatchMode) current_match_speed := Format("{}", A_TitleMatchModeSpeed) if (match_mode != "") { @@ -427,7 +410,6 @@ DetectHiddenWindows, %detect_hw% } - WinMinimize, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -462,7 +444,6 @@ DetectHiddenWindows, %detect_hw% } - WinMaximize, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -483,7 +464,6 @@ match_mode := command[7] match_speed := command[8] - current_match_mode := Format("{}", A_TitleMatchMode) current_match_speed := Format("{}", A_TitleMatchModeSpeed) if (match_mode != "") { @@ -498,7 +478,6 @@ DetectHiddenWindows, %detect_hw% } - WinRestore, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -511,7 +490,7 @@ AHKWinIsActive(ByRef command) { {% block AHKWinIsActive %} - global BOOLEANRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -535,9 +514,9 @@ } if WinActive(title, text, extitle, extext) { - response := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + response := FormatResponse("ahk.message.BooleanResponseMessage", 1) } else { - response := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + response := FormatResponse("ahk.message.BooleanResponseMessage", 0) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -548,7 +527,7 @@ AHKWinGetID(ByRef command) { {% block AHKWinGetID %} - global WINDOWRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -576,7 +555,7 @@ if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(WINDOWRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -587,7 +566,7 @@ AHKWinGetTitle(ByRef command) { {% block AHKWinGetTitle %} - global STRINGRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -616,13 +595,13 @@ SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% - return FormatResponse(STRINGRESPONSEMESSAGE, text) + return FormatResponse("ahk.message.StringResponseMessage", text) {% endblock AHKWinGetTitle %} } AHKWinGetIDLast(ByRef command) { {% block AHKWinGetIDLast %} - global WINDOWRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -650,7 +629,7 @@ if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(WINDOWRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -659,10 +638,9 @@ {% endblock AHKWinGetIDLast %} } - AHKWinGetPID(ByRef command) { {% block AHKWinGetPID %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -690,7 +668,7 @@ if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -699,10 +677,9 @@ {% endblock AHKWinGetPID %} } - AHKWinGetProcessName(ByRef command) { {% block AHKWinGetProcessName %} - global STRINGRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -730,7 +707,7 @@ if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -741,7 +718,7 @@ AHKWinGetProcessPath(ByRef command) { {% block AHKWinGetProcessPath %} - global STRINGRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -769,7 +746,7 @@ if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -778,10 +755,9 @@ {% endblock AHKWinGetProcessPath %} } - AHKWinGetCount(ByRef command) { {% block AHKWinGetCount %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -807,9 +783,9 @@ WinGet, output, Count, %title%, %text%, %extitle%, %extext% if (output = 0) { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } else { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -818,11 +794,9 @@ {% endblock AHKWinGetCount %} } - - AHKWinGetMinMax(ByRef command) { {% block AHKWinGetMinMax %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -850,7 +824,7 @@ if (output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -861,8 +835,7 @@ AHKWinGetControlList(ByRef command) { {% block AHKWinGetControlList %} - global EXCEPTIONRESPONSEMESSAGE - global WINDOWCONTROLLISTRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -886,7 +859,6 @@ DetectHiddenWindows, %detect_hw% } - WinGet, ahkid, ID, %title%, %text%, %extitle%, %extext% if (ahkid = "") { @@ -897,13 +869,13 @@ WinGet, ctrListID, ControlListHWND, %title%, %text%, %extitle%, %extext% if (ctrListID = "") { - return FormatResponse(WINDOWCONTROLLISTRESPONSEMESSAGE, Format("('{}', [])", ahkid)) + return FormatResponse("ahk.message.WindowControlListResponseMessage", Format("('{}', [])", ahkid)) } ctrListArr := StrSplit(ctrList, "`n") ctrListIDArr := StrSplit(ctrListID, "`n") if (ctrListArr.Length() != ctrListIDArr.Length()) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Control hwnd/class lists have unexpected lengths") + return FormatResponse("ahk.message.ExceptionResponseMessage", "Control hwnd/class lists have unexpected lengths") } output := Format("('{}', [", ahkid) @@ -914,7 +886,7 @@ } output .= "])" - response := FormatResponse(WINDOWCONTROLLISTRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.WindowControlListResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -924,7 +896,7 @@ AHKWinGetTransparent(ByRef command) { {% block AHKWinGetTransparent %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -949,7 +921,7 @@ } WinGet, output, Transparent, %title%, %text%, %extitle%, %extext% - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -958,9 +930,7 @@ } AHKWinGetTransColor(ByRef command) { {% block AHKWinGetTransColor %} - global STRINGRESPONSEMESSAGE - global INTEGERRESPONSEMESSAGE - global NOVALUERESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -985,7 +955,7 @@ } WinGet, output, TransColor, %title%, %text%, %extitle%, %extext% - response := FormatResponse(NOVALUERESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.NoValueResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -994,9 +964,7 @@ } AHKWinGetStyle(ByRef command) { {% block AHKWinGetStyle %} - global STRINGRESPONSEMESSAGE - global INTEGERRESPONSEMESSAGE - global NOVALUERESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -1021,7 +989,7 @@ } WinGet, output, Style, %title%, %text%, %extitle%, %extext% - response := FormatResponse(NOVALUERESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.NoValueResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -1030,9 +998,7 @@ } AHKWinGetExStyle(ByRef command) { {% block AHKWinGetExStyle %} - global STRINGRESPONSEMESSAGE - global INTEGERRESPONSEMESSAGE - global NOVALUERESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -1057,7 +1023,7 @@ } WinGet, output, ExStyle, %title%, %text%, %extitle%, %extext% - response := FormatResponse(NOVALUERESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.NoValueResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -1067,8 +1033,7 @@ AHKWinGetText(ByRef command) { {% block AHKWinGetText %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -1094,9 +1059,9 @@ WinGetText, output,%title%,%text%,%extitle%,%extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was an error getting window text") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was an error getting window text") } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -1106,8 +1071,6 @@ {% endblock AHKWinGetText %} } - - AHKWinSetTitle(ByRef command) { {% block AHKWinSetTitle %} new_title := command[2] @@ -1272,7 +1235,6 @@ {% endblock AHKWinHide %} } - AHKWinSetTop(ByRef command) { {% block AHKWinSetTop %} title := command[2] @@ -1407,7 +1369,7 @@ AHKWinSetStyle(ByRef command) { {% block AHKWinSetStyle %} - global BOOLEANRESPONSEMESSAGE + style := command[2] title := command[3] text := command[4] @@ -1431,12 +1393,11 @@ DetectHiddenWindows, %detect_hw% } - WinSet, Style, %style%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1447,7 +1408,7 @@ AHKWinSetExStyle(ByRef command) { {% block AHKWinSetExStyle %} - global BOOLEANRESPONSEMESSAGE + style := command[2] title := command[3] text := command[4] @@ -1471,12 +1432,11 @@ DetectHiddenWindows, %detect_hw% } - WinSet, ExStyle, %style%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1487,7 +1447,7 @@ AHKWinSetRegion(ByRef command) { {% block AHKWinSetRegion %} - global BOOLEANRESPONSEMESSAGE + options := command[2] title := command[3] text := command[4] @@ -1511,12 +1471,11 @@ DetectHiddenWindows, %detect_hw% } - WinSet, Region, %options%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1527,7 +1486,7 @@ AHKWinSetTransparent(ByRef command) { {% block AHKWinSetTransparent %} - global BOOLEANRESPONSEMESSAGE + transparency := command[2] title := command[3] text := command[4] @@ -1551,7 +1510,6 @@ DetectHiddenWindows, %detect_hw% } - WinSet, Transparent, %transparency%, %title%, %text%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1562,7 +1520,7 @@ AHKWinSetTransColor(ByRef command) { {% block AHKWinSetTransColor %} - global BOOLEANRESPONSEMESSAGE + color := command[2] title := command[3] text := command[4] @@ -1586,7 +1544,6 @@ DetectHiddenWindows, %detect_hw% } - WinSet, TransColor, %color%, %title%, %text%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -1599,8 +1556,7 @@ AHKImageSearch(ByRef command) { {% block AHKImageSearch %} - global COORDINATERESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + imagepath := command[6] x1 := command[2] y1 := command[3] @@ -1623,18 +1579,16 @@ ImageSearch, xpos, ypos,% x1,% y1,% x2,% y2, %imagepath% - if (coord_mode != "") { CoordMode, Pixel, %current_mode% } - if (ErrorLevel = 2) { - s := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "there was a problem that prevented the command from conducting the search (such as failure to open the image file or a badly formatted option)") + s := FormatResponse("ahk.message.ExceptionResponseMessage", "there was a problem that prevented the command from conducting the search (such as failure to open the image file or a badly formatted option)") } else if (ErrorLevel = 1) { s := FormatNoValueResponse() } else { - s := FormatResponse(COORDINATERESPONSEMESSAGE, Format("({}, {})", xpos, ypos)) + s := FormatResponse("ahk.message.CoordinateResponseMessage", Format("({}, {})", xpos, ypos)) } return s @@ -1643,7 +1597,7 @@ AHKPixelGetColor(ByRef command) { {% block AHKPixelGetColor %} - global STRINGRESPONSEMESSAGE + x := command[2] y := command[3] coord_mode := command[4] @@ -1662,14 +1616,13 @@ CoordMode, Pixel, %current_mode% } - return FormatResponse(STRINGRESPONSEMESSAGE, color) + return FormatResponse("ahk.message.StringResponseMessage", color) {% endblock AHKPixelGetColor %} } AHKPixelSearch(ByRef command) { {% block AHKPixelSearch %} - global COORDINATERESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + x1 := command[2] y1 := command[3] x2 := command[4] @@ -1695,20 +1648,19 @@ return FormatNoValueResponse() } else if (ErrorLevel = 0) { payload := Format("({}, {})", resultx, resulty) - return FormatResponse(COORDINATERESPONSEMESSAGE, payload) + return FormatResponse("ahk.message.CoordinateResponseMessage", payload) } else if (ErrorLevel = 2) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem conducting the pixel search (ErrorLevel 2)") + return FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem conducting the pixel search (ErrorLevel 2)") } else { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Unexpected error. This is probably a bug. Please report this at https://github.com/spyoungtech/ahk/issues") + return FormatResponse("ahk.message.ExceptionResponseMessage", "Unexpected error. This is probably a bug. Please report this at https://github.com/spyoungtech/ahk/issues") } {% endblock AHKPixelSearch %} } - AHKMouseGetPos(ByRef command) { {% block AHKMouseGetPos %} - global COORDINATERESPONSEMESSAGE + coord_mode := command[2] current_coord_mode := Format("{}", A_CoordModeMouse) if (coord_mode != "") { @@ -1717,7 +1669,7 @@ MouseGetPos, xpos, ypos payload := Format("({}, {})", xpos, ypos) - resp := FormatResponse(COORDINATERESPONSEMESSAGE, payload) + resp := FormatResponse("ahk.message.CoordinateResponseMessage", payload) if (coord_mode != "") { CoordMode, Mouse, %current_coord_mode% @@ -1729,10 +1681,6 @@ AHKKeyState(ByRef command) { {% block AHKKeyState %} - global INTEGERRESPONSEMESSAGE - global FLOATRESPONSEMESSAGE - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE keyname := command[2] mode := command[3] @@ -1747,15 +1695,15 @@ } if state is integer - return FormatResponse(INTEGERRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.IntegerResponseMessage", state) if state is float - return FormatResponse(FLOATRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.FloatResponseMessage", state) if state is alnum - return FormatResponse(STRINGRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.StringResponseMessage", state) - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.ExceptionResponseMessage", state) {% endblock AHKKeyState %} } @@ -1775,7 +1723,6 @@ {% endblock AHKMouseMove %} } - AHKClick(ByRef command) { {% block AHKClick %} x := command[2] @@ -1804,26 +1751,25 @@ AHKGetCoordMode(ByRef command) { {% block AHKGetCoordMode %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + target := command[2] if (target = "ToolTip") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeToolTip) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeToolTip) } if (target = "Pixel") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModePixel) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModePixel) } if (target = "Mouse") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeMouse) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeMouse) } if (target = "Caret") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeCaret) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeCaret) } if (target = "Menu") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeMenu) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeMenu) } - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Invalid coord mode") + return FormatResponse("ahk.message.ExceptionResponseMessage", "Invalid coord mode") {% endblock AHKGetCoordMode %} } @@ -1867,35 +1813,32 @@ AHKRegRead(ByRef command) { {% block RegRead %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + key_name := command[2] value_name := command[3] RegRead, output, %key_name%, %value_name% if (ErrorLevel = 1) { - resp := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("registry error: {}", A_LastError)) + resp := FormatResponse("ahk.message.ExceptionResponseMessage", Format("registry error: {}", A_LastError)) } else { - resp := FormatResponse(STRINGRESPONSEMESSAGE, Format("{}", output)) + resp := FormatResponse("ahk.message.StringResponseMessage", Format("{}", output)) } return resp {% endblock RegRead %} } - - AHKRegWrite(ByRef command) { {% block RegWrite %} - global EXCEPTIONRESPONSEMESSAGE + value_type := command[2] key_name := command[3] value_name := command[4] value := command[5] RegWrite, %value_type%, %key_name%, %value_name%, %value% if (ErrorLevel = 1) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("registry error: {}", A_LastError)) + return FormatResponse("ahk.message.ExceptionResponseMessage", Format("registry error: {}", A_LastError)) } return FormatNoValueResponse() @@ -1904,12 +1847,12 @@ AHKRegDelete(ByRef command) { {% block RegDelete %} - global EXCEPTIONRESPONSEMESSAGE + key_name := command[2] value_name := command[3] RegDelete, %key_name%, %value_name% if (ErrorLevel = 1) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("registry error: {}", A_LastError)) + return FormatResponse("ahk.message.ExceptionResponseMessage", Format("registry error: {}", A_LastError)) } return FormatNoValueResponse() @@ -1918,7 +1861,7 @@ AHKKeyWait(ByRef command) { {% block AHKKeyWait %} - global INTEGERRESPONSEMESSAGE + keyname := command[2] if (command.Length() = 2) { KeyWait,% keyname @@ -1926,7 +1869,7 @@ options := command[3] KeyWait,% keyname,% options } - return FormatResponse(INTEGERRESPONSEMESSAGE, ErrorLevel) + return FormatResponse("ahk.message.IntegerResponseMessage", ErrorLevel) {% endblock AHKKeyWait %} } @@ -1936,8 +1879,6 @@ {% endblock SetKeyDelay %} } - - AHKSend(ByRef command) { {% block AHKSend %} str := command[2] @@ -2001,7 +1942,6 @@ {% endblock AHKSendInput %} } - AHKSendEvent(ByRef command) { {% block AHKSendEvent %} str := command[2] @@ -2067,13 +2007,9 @@ {% endblock HideTrayTip %} } - - - AHKWinGetClass(ByRef command) { {% block AHKWinGetClass %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -2099,9 +2035,9 @@ WinGetClass, output,%title%,%text%,%extitle%,%extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was an error getting window class") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was an error getting window class") } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -2146,12 +2082,8 @@ {% endblock AHKWinActivate %} } - - - AHKWindowList(ByRef command) { {% block AHKWindowList %} - global WINDOWLISTRESPONSEMESSAGE current_detect_hw := Format("{}", A_DetectHiddenWindows) @@ -2182,7 +2114,7 @@ id := windows%A_Index% r .= id . "`," } - resp := FormatResponse(WINDOWLISTRESPONSEMESSAGE, r) + resp := FormatResponse("ahk.message.WindowListResponseMessage", r) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -2190,11 +2122,9 @@ {% endblock AHKWindowList %} } - - AHKControlClick(ByRef command) { {% block AHKControlClick %} - global EXCEPTIONRESPONSEMESSAGE + ctrl := command[2] title := command[3] text := command[4] @@ -2224,7 +2154,7 @@ ControlClick, %ctrl%, %title%, %text%, %button%, %click_count%, %options%, %exclude_title%, %exclude_text% if (ErrorLevel != 0) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Failed to click control") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "Failed to click control") } else { response := FormatNoValueResponse() } @@ -2239,8 +2169,7 @@ AHKControlGetText(ByRef command) { {% block AHKControlGetText %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + ctrl := command[2] title := command[3] text := command[4] @@ -2267,9 +2196,9 @@ ControlGetText, result, %ctrl%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem getting the text") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem getting the text") } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, result) + response := FormatResponse("ahk.message.StringResponseMessage", result) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -2279,11 +2208,9 @@ {% endblock AHKControlGetText %} } - AHKControlGetPos(ByRef command) { {% block AHKControlGetPos %} - global POSITIONRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + ctrl := command[2] title := command[3] text := command[4] @@ -2309,10 +2236,10 @@ ControlGetPos, x, y, w, h, %ctrl%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem getting the text") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem getting the text") } else { result := Format("({1:i}, {2:i}, {3:i}, {4:i})", x, y, w, h) - response := FormatResponse(PositionResponseMessage, result) + response := FormatResponse("ahk.message.PositionResponseMessage", result) } DetectHiddenWindows, %current_detect_hw% @@ -2321,7 +2248,6 @@ return response - {% endblock AHKControlGetPos %} } @@ -2358,39 +2284,34 @@ {% endblock AHKControlSend %} } - - - AHKWinFromMouse(ByRef command) { {% block AHKWinFromMouse %} - global WINDOWRESPONSEMESSAGE + MouseGetPos,,, MouseWin if (MouseWin = "") { return FormatNoValueResponse() } - return FormatResponse(WINDOWRESPONSEMESSAGE, MouseWin) + return FormatResponse("ahk.message.WindowResponseMessage", MouseWin) {% endblock AHKWinFromMouse %} } - AHKWinIsAlwaysOnTop(ByRef command) { {% block AHKWinIsAlwaysOnTop %} - global BOOLEANRESPONSEMESSAGE + title := command[2] WinGet, ExStyle, ExStyle, %title% if (ExStyle = "") return FormatNoValueResponse() if (ExStyle & 0x8) ; 0x8 is WS_EX_TOPMOST. - return FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + return FormatResponse("ahk.message.BooleanResponseMessage", 1) else - return FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + return FormatResponse("ahk.message.BooleanResponseMessage", 0) {% endblock AHKWinIsAlwaysOnTop %} } - AHKWinMove(ByRef command) { {% block AHKWinMove %} title := command[2] @@ -2432,8 +2353,6 @@ AHKWinGetPos(ByRef command) { {% block AHKWinGetPos %} - global POSITIONRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE title := command[2] text := command[3] @@ -2460,10 +2379,10 @@ WinGetPos, x, y, w, h, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem getting the position") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem getting the position") } else { result := Format("({1:i}, {2:i}, {3:i}, {4:i})", x, y, w, h) - response := FormatResponse(PositionResponseMessage, result) + response := FormatResponse("ahk.message.PositionResponseMessage", result) } DetectHiddenWindows, %current_detect_hw% @@ -2474,23 +2393,21 @@ {% endblock AHKWinGetPos %} } - AHKGetVolume(ByRef command) { {% block AHKGetVolume %} - global EXCEPTIONRESPONSEMESSAGE - global FLOATRESPONSEMESSAGE + device_number := command[2] try { SoundGetWaveVolume, retval, %device_number% } catch e { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("There was a problem getting the volume with device of index {} ({})", device_number, e.message)) + response := FormatResponse("ahk.message.ExceptionResponseMessage", Format("There was a problem getting the volume with device of index {} ({})", device_number, e.message)) return response } if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("There was a problem getting the volume with device of index {}", device_number)) + response := FormatResponse("ahk.message.ExceptionResponseMessage", Format("There was a problem getting the volume with device of index {}", device_number)) } else { - response := FormatResponse(FLOATRESPONSEMESSAGE, Format("{}", retval)) + response := FormatResponse("ahk.message.FloatResponseMessage", Format("{}", retval)) } return response {% endblock AHKGetVolume %} @@ -2507,14 +2424,14 @@ AHKSoundGet(ByRef command) { {% block AHKSoundGet %} - global STRINGRESPONSEMESSAGE + device_number := command[2] component_type := command[3] control_type := command[4] SoundGet, retval, %component_type%, %control_type%, %device_number% ; TODO interpret return type - return FormatResponse(STRINGRESPONSEMESSAGE, Format("{}", retval)) + return FormatResponse("ahk.message.StringResponseMessage", Format("{}", retval)) {% endblock AHKSoundGet %} } @@ -2555,8 +2472,8 @@ AHKEcho(ByRef command) { {% block AHKEcho %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, command) + arg := command[2] + return FormatResponse("ahk.message.StringResponseMessage", arg) {% endblock AHKEcho %} } @@ -2585,8 +2502,8 @@ AHKGetClipboard(ByRef command) { {% block AHKGetClipboard %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, Clipboard) + + return FormatResponse("ahk.message.StringResponseMessage", Clipboard) {% endblock AHKGetClipboard %} } @@ -2615,15 +2532,14 @@ } AHKClipWait(ByRef command) { - global TIMEOUTRESPONSEMESSAGE + timeout := command[2] wait_for_any_data := command[3] - ClipWait, %timeout%, %wait_for_any_data% if (ErrorLevel = 1) { - return FormatResponse(TIMEOUTRESPONSEMESSAGE, "timed out waiting for clipboard data") + return FormatResponse("ahk.message.TimeoutResponseMessage", "timed out waiting for clipboard data") } return FormatNoValueResponse() } @@ -2654,47 +2570,45 @@ } AHKGuiNew(ByRef command) { - global STRINGRESPONSEMESSAGE + options := command[2] title := command[3] Gui, New, %options%, %title% - return FormatResponse(STRINGRESPONSEMESSAGE, hwnd) + return FormatResponse("ahk.message.StringResponseMessage", hwnd) } AHKMsgBox(ByRef command) { - global TIMEOUTRESPONSEMESSAGE - global STRINGRESPONSEMESSAGE + options := command[2] title := command[3] text := command[4] timeout := command[5] MsgBox,% options, %title%, %text%, %timeout% IfMsgBox, Yes - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Yes") + ret := FormatResponse("ahk.message.StringResponseMessage", "Yes") IfMsgBox, No - ret := FormatResponse(STRINGRESPONSEMESSAGE, "No") + ret := FormatResponse("ahk.message.StringResponseMessage", "No") IfMsgBox, OK - ret := FormatResponse(STRINGRESPONSEMESSAGE, "OK") + ret := FormatResponse("ahk.message.StringResponseMessage", "OK") IfMsgBox, Cancel - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Cancel") + ret := FormatResponse("ahk.message.StringResponseMessage", "Cancel") IfMsgBox, Abort - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Abort") + ret := FormatResponse("ahk.message.StringResponseMessage", "Abort") IfMsgBox, Ignore - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Ignore") + ret := FormatResponse("ahk.message.StringResponseMessage", "Ignore") IfMsgBox, Retry - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Retry") + ret := FormatResponse("ahk.message.StringResponseMessage", "Retry") IfMsgBox, Continue - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Continue") + ret := FormatResponse("ahk.message.StringResponseMessage", "Continue") IfMsgBox, TryAgain - ret := FormatResponse(STRINGRESPONSEMESSAGE, "TryAgain") + ret := FormatResponse("ahk.message.StringResponseMessage", "TryAgain") IfMsgBox, Timeout - ret := FormatResponse(TIMEOUTRESPONSEMESSAGE, "MsgBox timed out") + ret := FormatResponse("ahk.message.TimeoutResponseMessage", "MsgBox timed out") return ret } AHKInputBox(ByRef command) { - global STRINGRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE + title := command[2] prompt := command[3] hide := command[4] @@ -2708,17 +2622,17 @@ InputBox, output, %title%, %prompt%, %hide%, %width%, %height%, %x%, %y%, %locale%, %timeout%, %default% if (ErrorLevel = 2) { - ret := FormatResponse(TIMEOUTRESPONSEMESSAGE, "Input box timed out") + ret := FormatResponse("ahk.message.TimeoutResponseMessage", "Input box timed out") } else if (ErrorLevel = 1) { ret := FormatNoValueResponse() } else { - ret := FormatResponse(STRINGRESPONSEMESSAGE, output) + ret := FormatResponse("ahk.message.StringResponseMessage", output) } return ret } AHKFileSelectFile(byRef command) { - global STRINGRESPONSEMESSAGE + options := command[2] root := command[3] title := command[4] @@ -2727,13 +2641,13 @@ if (ErrorLevel = 1) { ret := FormatNoValueResponse() } else { - ret := FormatResponse(STRINGRESPONSEMESSAGE, output) + ret := FormatResponse("ahk.message.StringResponseMessage", output) } return ret } AHKFileSelectFolder(byRef command) { - global STRINGRESPONSEMESSAGE + starting_folder := command[2] options := command[3] prompt := command[4] @@ -2743,7 +2657,7 @@ if (ErrorLevel = 1) { ret := FormatNoValueResponse() } else { - ret := FormatResponse(STRINGRESPONSEMESSAGE, output) + ret := FormatResponse("ahk.message.StringResponseMessage", output) } return ret } @@ -2771,7 +2685,6 @@ pdwSkip := 0 ; We don't use any headers or preamble, so this is zero pdwFlags := 0 ; We don't need this, so make it null - ; The first call calculates the required size. The result is written to pbBinary success := DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &pszString, "UInt", cchString, "UInt", dwFlags, "UInt", getsize, "UIntP", buff_size, "Int", pdwSkip, "Int", pdwFlags ) if (success = 0) { @@ -2799,7 +2712,6 @@ ; [out, optional] LPSTR pszString: A pointer to the string, or null (0) to calculate size ; [in, out] DWORD *pcchString: A pointer to a DWORD variable that contains the size, in TCHARs, of the pszString buffer - cbBinary := StrLen(data) * (A_IsUnicode ? 2 : 1) if (cbBinary = 0) { return "" @@ -2813,7 +2725,6 @@ throw Exception(msg, -1) } - VarSetCapacity(ret, buff_size * (A_IsUnicode ? 2 : 1)) ; Now we do the conversion to base64 and rteturn the string @@ -2826,7 +2737,6 @@ return ret } - ; End of included content CommandArrayFromQuery(ByRef text) { @@ -2868,14 +2778,14 @@ } catch e { {% block function_error_handle %} message := Format("Error occurred in {}. The error message was: {}", e.What, e.message) - pyresp := FormatResponse(EXCEPTIONRESPONSEMESSAGE, message) + pyresp := FormatResponse("ahk.message.ExceptionResponseMessage", message) {% endblock function_error_handle %} } {% block send_response %} if (pyresp) { FileAppend, %pyresp%, *, UTF-8 } else { - msg := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("Unknown Error when calling {}", func)) + msg := FormatResponse("ahk.message.ExceptionResponseMessage", Format("Unknown Error when calling {}", func)) FileAppend, %msg%, *, UTF-8 } {% endblock send_response %} diff --git a/ahk/_sync/transport.py b/ahk/_sync/transport.py index 11ccb00..e786a19 100644 --- a/ahk/_sync/transport.py +++ b/ahk/_sync/transport.py @@ -631,7 +631,7 @@ def __init__( directives: Optional[list[Directive | Type[Directive]]] = None, jinja_loader: Optional[jinja2.BaseLoader] = None, template: Optional[jinja2.Template] = None, - extensions: list[Extension] | None = None + extensions: list[Extension] | None = None, ): self._extensions = extensions or [] self._proc: Optional[SyncAHKProcess] @@ -687,7 +687,13 @@ def _render_script(self, template: Optional[jinja2.Template] = None, **kwargs: A template = self._template kwargs['daemon'] = self.__template message_types = {str(tom, 'utf-8'): c.__name__.upper() for tom, c in _message_registry.items()} - return template.render(directives=self._directives, message_types=message_types, extensions=self._extensions, **kwargs) + return template.render( + directives=self._directives, + message_types=message_types, + message_registry=_message_registry, + extensions=self._extensions, + **kwargs, + ) @property def lock(self) -> Any: diff --git a/ahk/message.py b/ahk/message.py index be10359..3a0f131 100644 --- a/ahk/message.py +++ b/ahk/message.py @@ -100,16 +100,18 @@ def tom_generator() -> Generator[bytes, None, None]: class ResponseMessage: - type: Optional[str] = None _type_order_mark = next(TOMS) + @classmethod + def fqn(cls) -> str: + return f'{cls.__module__}.{cls.__qualname__}' + @classmethod def __init_subclass__(cls: Type[T_ResponseMessageType], **kwargs: Any) -> None: tom = next(TOMS) cls._type_order_mark = tom assert tom not in _message_registry, f'cannot register class {cls!r} with TOM {tom!r} which is already in use' _message_registry[tom] = cls - assert cls.type is not None, f'must assign a type for class {cls!r}' super().__init_subclass__(**kwargs) def __init__(self, raw_content: bytes, engine: Optional[Union[AsyncAHK, AHK]] = None): @@ -117,7 +119,7 @@ def __init__(self, raw_content: bytes, engine: Optional[Union[AsyncAHK, AHK]] = self._engine: Optional[Union[AsyncAHK, AHK]] = engine def __repr__(self) -> str: - return f'ResponseMessage' + return f'ResponseMessage' @staticmethod def _tom_lookup(tom: bytes) -> 'ResponseMessageClassTypes': @@ -147,8 +149,6 @@ def unpack(self) -> Any: class TupleResponseMessage(ResponseMessage): - type = 'tuple' - def unpack(self) -> Tuple[Any, ...]: s = self._raw_content.decode(encoding='utf-8') val = ast.literal_eval(s) @@ -157,8 +157,6 @@ def unpack(self) -> Tuple[Any, ...]: class CoordinateResponseMessage(ResponseMessage): - type = 'coordinate' - def unpack(self) -> Tuple[int, int]: s = self._raw_content.decode(encoding='utf-8') val = ast.literal_eval(s) @@ -168,8 +166,6 @@ def unpack(self) -> Tuple[int, int]: class IntegerResponseMessage(ResponseMessage): - type = 'integer' - def unpack(self) -> int: s = self._raw_content.decode(encoding='utf-8') val = ast.literal_eval(s) @@ -178,8 +174,6 @@ def unpack(self) -> int: class BooleanResponseMessage(IntegerResponseMessage): - type = 'boolean' - def unpack(self) -> bool: val = super().unpack() assert val in (1, 0) @@ -187,15 +181,11 @@ def unpack(self) -> bool: class StringResponseMessage(ResponseMessage): - type = 'string' - def unpack(self) -> str: return self._raw_content.decode('utf-8') class WindowListResponseMessage(ResponseMessage): - type = 'windowlist' - def unpack(self) -> Union[List[Window], List[AsyncWindow]]: from ._async.engine import AsyncAHK from ._async.window import AsyncWindow @@ -216,8 +206,6 @@ def unpack(self) -> Union[List[Window], List[AsyncWindow]]: class NoValueResponseMessage(ResponseMessage): - type = 'novalue' - def unpack(self) -> None: assert self._raw_content == b'\xee\x80\x80', f'Unexpected or Malformed response: {self._raw_content!r}' return None @@ -228,7 +216,6 @@ class AHKExecutionException(Exception): class ExceptionResponseMessage(ResponseMessage): - type = 'exception' _exception_type: Type[Exception] = AHKExecutionException def unpack(self) -> NoReturn: @@ -237,8 +224,6 @@ def unpack(self) -> NoReturn: class WindowControlListResponseMessage(ResponseMessage): - type = 'windowcontrollist' - def unpack(self) -> Union[List[AsyncControl], List[Control]]: from ._async.engine import AsyncAHK from ._async.window import AsyncWindow, AsyncControl @@ -272,8 +257,6 @@ def unpack(self) -> Union[List[AsyncControl], List[Control]]: class WindowResponseMessage(ResponseMessage): - type = 'window' - def unpack(self) -> Union[Window, AsyncWindow]: from ._async.engine import AsyncAHK from ._async.window import AsyncWindow @@ -293,8 +276,6 @@ def unpack(self) -> Union[Window, AsyncWindow]: class PositionResponseMessage(TupleResponseMessage): - type = 'position' - def unpack(self) -> Position: resp = super().unpack() if not len(resp) == 4: @@ -304,8 +285,6 @@ def unpack(self) -> Position: class FloatResponseMessage(ResponseMessage): - type = 'float' - def unpack(self) -> float: s = self._raw_content.decode(encoding='utf-8') val = ast.literal_eval(s) @@ -314,13 +293,10 @@ def unpack(self) -> float: class TimeoutResponseMessage(ExceptionResponseMessage): - type = 'timeoutexception' _exception_type = TimeoutError class B64BinaryResponseMessage(ResponseMessage): - type = 'binary' - def unpack(self) -> bytes: b64_content = self._raw_content b = base64.b64decode(b64_content) diff --git a/ahk/templates/daemon.ahk b/ahk/templates/daemon.ahk index 22b7ab8..3daf2c7 100644 --- a/ahk/templates/daemon.ahk +++ b/ahk/templates/daemon.ahk @@ -25,30 +25,26 @@ {% endblock directives %} {% block message_types %} -{% for tom, name in message_types.items() %} -{{ name }} := "{{ tom }}" -{% endfor %} +MESSAGE_TYPES := Object({% for tom, msg_class in message_registry.items() %}"{{ msg_class.fqn() }}", "{{ tom.decode('utf-8') }}"{% if not loop.last %}, {% endif %}{% endfor %}) {% endblock message_types %} - NOVALUE_SENTINEL := Chr(57344) FormatResponse(ByRef MessageType, ByRef payload) { + global MESSAGE_TYPES newline_count := CountNewlines(payload) - response := Format("{}`n{}`n{}`n", MessageType, newline_count, payload) + response := Format("{}`n{}`n{}`n", MESSAGE_TYPES[MessageType], newline_count, payload) return response } FormatNoValueResponse() { global NOVALUE_SENTINEL - global NOVALUERESPONSEMESSAGE - return FormatResponse(NOVALUERESPONSEMESSAGE, NOVALUE_SENTINEL) + return FormatResponse("ahk.message.NoValueResponseMessage", NOVALUE_SENTINEL) } FormatBinaryResponse(ByRef bin) { - global B64BINARYRESPONSEMESSAGE b64 := b64encode(bin) - return FormatResponse(B64BINARYRESPONSEMESSAGE, b64) + return FormatResponse("ahk.message.B64BinaryResponseMessage", b64) } AHKSetDetectHiddenWindows(ByRef command) { @@ -75,15 +71,15 @@ AHKSetTitleMatchMode(ByRef command) { AHKGetTitleMatchMode(ByRef command) { {% block AHKGetTitleMatchMode %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, A_TitleMatchMode) + + return FormatResponse("ahk.message.StringResponseMessage", A_TitleMatchMode) {% endblock AHKGetTitleMatchMode %} } AHKGetTitleMatchSpeed(ByRef command) { {% block AHKGetTitleMatchSpeed %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, A_TitleMatchModeSpeed) + + return FormatResponse("ahk.message.StringResponseMessage", A_TitleMatchModeSpeed) {% endblock AHKGetTitleMatchSpeed %} } @@ -97,14 +93,14 @@ AHKSetSendLevel(ByRef command) { AHKGetSendLevel(ByRef command) { {% block AHKGetSendLevel %} - global INTEGERRESPONSEMESSAGE - return FormatResponse(INTEGERRESPONSEMESSAGE, A_SendLevel) + + return FormatResponse("ahk.message.IntegerResponseMessage", A_SendLevel) {% endblock AHKGetSendLevel %} } AHKWinExist(ByRef command) { {% block AHKWinExist %} - global BOOLEANRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -129,9 +125,9 @@ AHKWinExist(ByRef command) { } if WinExist(title, text, extitle, extext) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } DetectHiddenWindows, %current_detect_hw% @@ -167,14 +163,12 @@ AHKWinClose(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinClose, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% - return FormatNoValueResponse() {% endblock AHKWinClose %} } @@ -204,7 +198,6 @@ AHKWinKill(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinKill, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -217,8 +210,6 @@ AHKWinKill(ByRef command) { AHKWinWait(ByRef command) { {% block AHKWinWait %} - global WINDOWRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -247,10 +238,10 @@ AHKWinWait(ByRef command) { WinWait, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { WinGet, output, ID - resp := FormatResponse(WINDOWRESPONSEMESSAGE, output) + resp := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -261,11 +252,8 @@ AHKWinWait(ByRef command) { {% endblock AHKWinWait %} } - AHKWinWaitActive(ByRef command) { {% block AHKWinWaitActive %} - global WINDOWRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -294,10 +282,10 @@ AHKWinWaitActive(ByRef command) { WinWaitActive, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { WinGet, output, ID - resp := FormatResponse(WINDOWRESPONSEMESSAGE, output) + resp := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -308,11 +296,8 @@ AHKWinWaitActive(ByRef command) { {% endblock AHKWinWaitActive %} } - AHKWinWaitNotActive(ByRef command) { {% block AHKWinWaitNotActive %} - global WINDOWRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -341,10 +326,10 @@ AHKWinWaitNotActive(ByRef command) { WinWaitNotActive, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { WinGet, output, ID - resp := FormatResponse(WINDOWRESPONSEMESSAGE, output) + resp := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -357,7 +342,6 @@ AHKWinWaitNotActive(ByRef command) { AHKWinWaitClose(ByRef command) { {% block AHKWinWaitClose %} - global TIMEOUTRESPONSEMESSAGE title := command[2] text := command[3] @@ -386,7 +370,7 @@ AHKWinWaitClose(ByRef command) { WinWaitClose, %title%, %text%,, %extitle%, %extext% } if (ErrorLevel = 1) { - resp := FormatResponse(TIMEOUTRESPONSEMESSAGE, "WinWait timed out waiting for window") + resp := FormatResponse("ahk.message.TimeoutResponseMessage", "WinWait timed out waiting for window") } else { resp := FormatNoValueResponse() } @@ -409,7 +393,6 @@ AHKWinMinimize(ByRef command) { match_mode := command[7] match_speed := command[8] - current_match_mode := Format("{}", A_TitleMatchMode) current_match_speed := Format("{}", A_TitleMatchModeSpeed) if (match_mode != "") { @@ -424,7 +407,6 @@ AHKWinMinimize(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinMinimize, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -459,7 +441,6 @@ AHKWinMaximize(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinMaximize, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -480,7 +461,6 @@ AHKWinRestore(ByRef command) { match_mode := command[7] match_speed := command[8] - current_match_mode := Format("{}", A_TitleMatchMode) current_match_speed := Format("{}", A_TitleMatchModeSpeed) if (match_mode != "") { @@ -495,7 +475,6 @@ AHKWinRestore(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinRestore, %title%, %text%, %secondstowait%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -508,7 +487,7 @@ AHKWinRestore(ByRef command) { AHKWinIsActive(ByRef command) { {% block AHKWinIsActive %} - global BOOLEANRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -532,9 +511,9 @@ AHKWinIsActive(ByRef command) { } if WinActive(title, text, extitle, extext) { - response := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + response := FormatResponse("ahk.message.BooleanResponseMessage", 1) } else { - response := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + response := FormatResponse("ahk.message.BooleanResponseMessage", 0) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -545,7 +524,7 @@ AHKWinIsActive(ByRef command) { AHKWinGetID(ByRef command) { {% block AHKWinGetID %} - global WINDOWRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -573,7 +552,7 @@ AHKWinGetID(ByRef command) { if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(WINDOWRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -584,7 +563,7 @@ AHKWinGetID(ByRef command) { AHKWinGetTitle(ByRef command) { {% block AHKWinGetTitle %} - global STRINGRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -613,13 +592,13 @@ AHKWinGetTitle(ByRef command) { SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% - return FormatResponse(STRINGRESPONSEMESSAGE, text) + return FormatResponse("ahk.message.StringResponseMessage", text) {% endblock AHKWinGetTitle %} } AHKWinGetIDLast(ByRef command) { {% block AHKWinGetIDLast %} - global WINDOWRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -647,7 +626,7 @@ AHKWinGetIDLast(ByRef command) { if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(WINDOWRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.WindowResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -656,10 +635,9 @@ AHKWinGetIDLast(ByRef command) { {% endblock AHKWinGetIDLast %} } - AHKWinGetPID(ByRef command) { {% block AHKWinGetPID %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -687,7 +665,7 @@ AHKWinGetPID(ByRef command) { if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -696,10 +674,9 @@ AHKWinGetPID(ByRef command) { {% endblock AHKWinGetPID %} } - AHKWinGetProcessName(ByRef command) { {% block AHKWinGetProcessName %} - global STRINGRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -727,7 +704,7 @@ AHKWinGetProcessName(ByRef command) { if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -738,7 +715,7 @@ AHKWinGetProcessName(ByRef command) { AHKWinGetProcessPath(ByRef command) { {% block AHKWinGetProcessPath %} - global STRINGRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -766,7 +743,7 @@ AHKWinGetProcessPath(ByRef command) { if (output = 0 || output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -775,10 +752,9 @@ AHKWinGetProcessPath(ByRef command) { {% endblock AHKWinGetProcessPath %} } - AHKWinGetCount(ByRef command) { {% block AHKWinGetCount %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -804,9 +780,9 @@ AHKWinGetCount(ByRef command) { WinGet, output, Count, %title%, %text%, %extitle%, %extext% if (output = 0) { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } else { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -815,11 +791,9 @@ AHKWinGetCount(ByRef command) { {% endblock AHKWinGetCount %} } - - AHKWinGetMinMax(ByRef command) { {% block AHKWinGetMinMax %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -847,7 +821,7 @@ AHKWinGetMinMax(ByRef command) { if (output = "") { response := FormatNoValueResponse() } else { - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -858,8 +832,7 @@ AHKWinGetMinMax(ByRef command) { AHKWinGetControlList(ByRef command) { {% block AHKWinGetControlList %} - global EXCEPTIONRESPONSEMESSAGE - global WINDOWCONTROLLISTRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -883,7 +856,6 @@ AHKWinGetControlList(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinGet, ahkid, ID, %title%, %text%, %extitle%, %extext% if (ahkid = "") { @@ -894,13 +866,13 @@ AHKWinGetControlList(ByRef command) { WinGet, ctrListID, ControlListHWND, %title%, %text%, %extitle%, %extext% if (ctrListID = "") { - return FormatResponse(WINDOWCONTROLLISTRESPONSEMESSAGE, Format("('{}', [])", ahkid)) + return FormatResponse("ahk.message.WindowControlListResponseMessage", Format("('{}', [])", ahkid)) } ctrListArr := StrSplit(ctrList, "`n") ctrListIDArr := StrSplit(ctrListID, "`n") if (ctrListArr.Length() != ctrListIDArr.Length()) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Control hwnd/class lists have unexpected lengths") + return FormatResponse("ahk.message.ExceptionResponseMessage", "Control hwnd/class lists have unexpected lengths") } output := Format("('{}', [", ahkid) @@ -911,7 +883,7 @@ AHKWinGetControlList(ByRef command) { } output .= "])" - response := FormatResponse(WINDOWCONTROLLISTRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.WindowControlListResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -921,7 +893,7 @@ AHKWinGetControlList(ByRef command) { AHKWinGetTransparent(ByRef command) { {% block AHKWinGetTransparent %} - global INTEGERRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -946,7 +918,7 @@ AHKWinGetTransparent(ByRef command) { } WinGet, output, Transparent, %title%, %text%, %extitle%, %extext% - response := FormatResponse(INTEGERRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.IntegerResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -955,9 +927,7 @@ AHKWinGetTransparent(ByRef command) { } AHKWinGetTransColor(ByRef command) { {% block AHKWinGetTransColor %} - global STRINGRESPONSEMESSAGE - global INTEGERRESPONSEMESSAGE - global NOVALUERESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -982,7 +952,7 @@ AHKWinGetTransColor(ByRef command) { } WinGet, output, TransColor, %title%, %text%, %extitle%, %extext% - response := FormatResponse(NOVALUERESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.NoValueResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -991,9 +961,7 @@ AHKWinGetTransColor(ByRef command) { } AHKWinGetStyle(ByRef command) { {% block AHKWinGetStyle %} - global STRINGRESPONSEMESSAGE - global INTEGERRESPONSEMESSAGE - global NOVALUERESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -1018,7 +986,7 @@ AHKWinGetStyle(ByRef command) { } WinGet, output, Style, %title%, %text%, %extitle%, %extext% - response := FormatResponse(NOVALUERESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.NoValueResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -1027,9 +995,7 @@ AHKWinGetStyle(ByRef command) { } AHKWinGetExStyle(ByRef command) { {% block AHKWinGetExStyle %} - global STRINGRESPONSEMESSAGE - global INTEGERRESPONSEMESSAGE - global NOVALUERESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -1054,7 +1020,7 @@ AHKWinGetExStyle(ByRef command) { } WinGet, output, ExStyle, %title%, %text%, %extitle%, %extext% - response := FormatResponse(NOVALUERESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.NoValueResponseMessage", output) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -1064,8 +1030,7 @@ AHKWinGetExStyle(ByRef command) { AHKWinGetText(ByRef command) { {% block AHKWinGetText %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -1091,9 +1056,9 @@ AHKWinGetText(ByRef command) { WinGetText, output,%title%,%text%,%extitle%,%extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was an error getting window text") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was an error getting window text") } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -1103,8 +1068,6 @@ AHKWinGetText(ByRef command) { {% endblock AHKWinGetText %} } - - AHKWinSetTitle(ByRef command) { {% block AHKWinSetTitle %} new_title := command[2] @@ -1269,7 +1232,6 @@ AHKWinHide(ByRef command) { {% endblock AHKWinHide %} } - AHKWinSetTop(ByRef command) { {% block AHKWinSetTop %} title := command[2] @@ -1404,7 +1366,7 @@ AHKWinSetRedraw(ByRef command) { AHKWinSetStyle(ByRef command) { {% block AHKWinSetStyle %} - global BOOLEANRESPONSEMESSAGE + style := command[2] title := command[3] text := command[4] @@ -1428,12 +1390,11 @@ AHKWinSetStyle(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinSet, Style, %style%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1444,7 +1405,7 @@ AHKWinSetStyle(ByRef command) { AHKWinSetExStyle(ByRef command) { {% block AHKWinSetExStyle %} - global BOOLEANRESPONSEMESSAGE + style := command[2] title := command[3] text := command[4] @@ -1468,12 +1429,11 @@ AHKWinSetExStyle(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinSet, ExStyle, %style%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1484,7 +1444,7 @@ AHKWinSetExStyle(ByRef command) { AHKWinSetRegion(ByRef command) { {% block AHKWinSetRegion %} - global BOOLEANRESPONSEMESSAGE + options := command[2] title := command[3] text := command[4] @@ -1508,12 +1468,11 @@ AHKWinSetRegion(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinSet, Region, %options%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 0) } else { - resp := FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + resp := FormatResponse("ahk.message.BooleanResponseMessage", 1) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1524,7 +1483,7 @@ AHKWinSetRegion(ByRef command) { AHKWinSetTransparent(ByRef command) { {% block AHKWinSetTransparent %} - global BOOLEANRESPONSEMESSAGE + transparency := command[2] title := command[3] text := command[4] @@ -1548,7 +1507,6 @@ AHKWinSetTransparent(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinSet, Transparent, %transparency%, %title%, %text%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -1559,7 +1517,7 @@ AHKWinSetTransparent(ByRef command) { AHKWinSetTransColor(ByRef command) { {% block AHKWinSetTransColor %} - global BOOLEANRESPONSEMESSAGE + color := command[2] title := command[3] text := command[4] @@ -1583,7 +1541,6 @@ AHKWinSetTransColor(ByRef command) { DetectHiddenWindows, %detect_hw% } - WinSet, TransColor, %color%, %title%, %text%, %extitle%, %extext% DetectHiddenWindows, %current_detect_hw% @@ -1596,8 +1553,7 @@ AHKWinSetTransColor(ByRef command) { AHKImageSearch(ByRef command) { {% block AHKImageSearch %} - global COORDINATERESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + imagepath := command[6] x1 := command[2] y1 := command[3] @@ -1620,18 +1576,16 @@ AHKImageSearch(ByRef command) { ImageSearch, xpos, ypos,% x1,% y1,% x2,% y2, %imagepath% - if (coord_mode != "") { CoordMode, Pixel, %current_mode% } - if (ErrorLevel = 2) { - s := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "there was a problem that prevented the command from conducting the search (such as failure to open the image file or a badly formatted option)") + s := FormatResponse("ahk.message.ExceptionResponseMessage", "there was a problem that prevented the command from conducting the search (such as failure to open the image file or a badly formatted option)") } else if (ErrorLevel = 1) { s := FormatNoValueResponse() } else { - s := FormatResponse(COORDINATERESPONSEMESSAGE, Format("({}, {})", xpos, ypos)) + s := FormatResponse("ahk.message.CoordinateResponseMessage", Format("({}, {})", xpos, ypos)) } return s @@ -1640,7 +1594,7 @@ AHKImageSearch(ByRef command) { AHKPixelGetColor(ByRef command) { {% block AHKPixelGetColor %} - global STRINGRESPONSEMESSAGE + x := command[2] y := command[3] coord_mode := command[4] @@ -1659,14 +1613,13 @@ AHKPixelGetColor(ByRef command) { CoordMode, Pixel, %current_mode% } - return FormatResponse(STRINGRESPONSEMESSAGE, color) + return FormatResponse("ahk.message.StringResponseMessage", color) {% endblock AHKPixelGetColor %} } AHKPixelSearch(ByRef command) { {% block AHKPixelSearch %} - global COORDINATERESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + x1 := command[2] y1 := command[3] x2 := command[4] @@ -1692,20 +1645,19 @@ AHKPixelSearch(ByRef command) { return FormatNoValueResponse() } else if (ErrorLevel = 0) { payload := Format("({}, {})", resultx, resulty) - return FormatResponse(COORDINATERESPONSEMESSAGE, payload) + return FormatResponse("ahk.message.CoordinateResponseMessage", payload) } else if (ErrorLevel = 2) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem conducting the pixel search (ErrorLevel 2)") + return FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem conducting the pixel search (ErrorLevel 2)") } else { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Unexpected error. This is probably a bug. Please report this at https://github.com/spyoungtech/ahk/issues") + return FormatResponse("ahk.message.ExceptionResponseMessage", "Unexpected error. This is probably a bug. Please report this at https://github.com/spyoungtech/ahk/issues") } {% endblock AHKPixelSearch %} } - AHKMouseGetPos(ByRef command) { {% block AHKMouseGetPos %} - global COORDINATERESPONSEMESSAGE + coord_mode := command[2] current_coord_mode := Format("{}", A_CoordModeMouse) if (coord_mode != "") { @@ -1714,7 +1666,7 @@ AHKMouseGetPos(ByRef command) { MouseGetPos, xpos, ypos payload := Format("({}, {})", xpos, ypos) - resp := FormatResponse(COORDINATERESPONSEMESSAGE, payload) + resp := FormatResponse("ahk.message.CoordinateResponseMessage", payload) if (coord_mode != "") { CoordMode, Mouse, %current_coord_mode% @@ -1726,10 +1678,6 @@ AHKMouseGetPos(ByRef command) { AHKKeyState(ByRef command) { {% block AHKKeyState %} - global INTEGERRESPONSEMESSAGE - global FLOATRESPONSEMESSAGE - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE keyname := command[2] mode := command[3] @@ -1744,15 +1692,15 @@ AHKKeyState(ByRef command) { } if state is integer - return FormatResponse(INTEGERRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.IntegerResponseMessage", state) if state is float - return FormatResponse(FLOATRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.FloatResponseMessage", state) if state is alnum - return FormatResponse(STRINGRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.StringResponseMessage", state) - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, state) + return FormatResponse("ahk.message.ExceptionResponseMessage", state) {% endblock AHKKeyState %} } @@ -1772,7 +1720,6 @@ AHKMouseMove(ByRef command) { {% endblock AHKMouseMove %} } - AHKClick(ByRef command) { {% block AHKClick %} x := command[2] @@ -1801,26 +1748,25 @@ AHKClick(ByRef command) { AHKGetCoordMode(ByRef command) { {% block AHKGetCoordMode %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + target := command[2] if (target = "ToolTip") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeToolTip) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeToolTip) } if (target = "Pixel") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModePixel) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModePixel) } if (target = "Mouse") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeMouse) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeMouse) } if (target = "Caret") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeCaret) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeCaret) } if (target = "Menu") { - return FormatResponse(STRINGRESPONSEMESSAGE, A_CoordModeMenu) + return FormatResponse("ahk.message.StringResponseMessage", A_CoordModeMenu) } - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Invalid coord mode") + return FormatResponse("ahk.message.ExceptionResponseMessage", "Invalid coord mode") {% endblock AHKGetCoordMode %} } @@ -1864,35 +1810,32 @@ AHKMouseClickDrag(ByRef command) { AHKRegRead(ByRef command) { {% block RegRead %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + key_name := command[2] value_name := command[3] RegRead, output, %key_name%, %value_name% if (ErrorLevel = 1) { - resp := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("registry error: {}", A_LastError)) + resp := FormatResponse("ahk.message.ExceptionResponseMessage", Format("registry error: {}", A_LastError)) } else { - resp := FormatResponse(STRINGRESPONSEMESSAGE, Format("{}", output)) + resp := FormatResponse("ahk.message.StringResponseMessage", Format("{}", output)) } return resp {% endblock RegRead %} } - - AHKRegWrite(ByRef command) { {% block RegWrite %} - global EXCEPTIONRESPONSEMESSAGE + value_type := command[2] key_name := command[3] value_name := command[4] value := command[5] RegWrite, %value_type%, %key_name%, %value_name%, %value% if (ErrorLevel = 1) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("registry error: {}", A_LastError)) + return FormatResponse("ahk.message.ExceptionResponseMessage", Format("registry error: {}", A_LastError)) } return FormatNoValueResponse() @@ -1901,12 +1844,12 @@ AHKRegWrite(ByRef command) { AHKRegDelete(ByRef command) { {% block RegDelete %} - global EXCEPTIONRESPONSEMESSAGE + key_name := command[2] value_name := command[3] RegDelete, %key_name%, %value_name% if (ErrorLevel = 1) { - return FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("registry error: {}", A_LastError)) + return FormatResponse("ahk.message.ExceptionResponseMessage", Format("registry error: {}", A_LastError)) } return FormatNoValueResponse() @@ -1915,7 +1858,7 @@ AHKRegDelete(ByRef command) { AHKKeyWait(ByRef command) { {% block AHKKeyWait %} - global INTEGERRESPONSEMESSAGE + keyname := command[2] if (command.Length() = 2) { KeyWait,% keyname @@ -1923,7 +1866,7 @@ AHKKeyWait(ByRef command) { options := command[3] KeyWait,% keyname,% options } - return FormatResponse(INTEGERRESPONSEMESSAGE, ErrorLevel) + return FormatResponse("ahk.message.IntegerResponseMessage", ErrorLevel) {% endblock AHKKeyWait %} } @@ -1933,8 +1876,6 @@ SetKeyDelay(ByRef command) { {% endblock SetKeyDelay %} } - - AHKSend(ByRef command) { {% block AHKSend %} str := command[2] @@ -1998,7 +1939,6 @@ AHKSendInput(ByRef command) { {% endblock AHKSendInput %} } - AHKSendEvent(ByRef command) { {% block AHKSendEvent %} str := command[2] @@ -2064,13 +2004,9 @@ HideTrayTip(ByRef command) { {% endblock HideTrayTip %} } - - - AHKWinGetClass(ByRef command) { {% block AHKWinGetClass %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + title := command[2] text := command[3] extitle := command[4] @@ -2096,9 +2032,9 @@ AHKWinGetClass(ByRef command) { WinGetClass, output,%title%,%text%,%extitle%,%extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was an error getting window class") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was an error getting window class") } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, output) + response := FormatResponse("ahk.message.StringResponseMessage", output) } DetectHiddenWindows, %current_detect_hw% @@ -2143,12 +2079,8 @@ AHKWinActivate(ByRef command) { {% endblock AHKWinActivate %} } - - - AHKWindowList(ByRef command) { {% block AHKWindowList %} - global WINDOWLISTRESPONSEMESSAGE current_detect_hw := Format("{}", A_DetectHiddenWindows) @@ -2179,7 +2111,7 @@ AHKWindowList(ByRef command) { id := windows%A_Index% r .= id . "`," } - resp := FormatResponse(WINDOWLISTRESPONSEMESSAGE, r) + resp := FormatResponse("ahk.message.WindowListResponseMessage", r) DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% SetTitleMatchMode, %current_match_speed% @@ -2187,11 +2119,9 @@ AHKWindowList(ByRef command) { {% endblock AHKWindowList %} } - - AHKControlClick(ByRef command) { {% block AHKControlClick %} - global EXCEPTIONRESPONSEMESSAGE + ctrl := command[2] title := command[3] text := command[4] @@ -2221,7 +2151,7 @@ AHKControlClick(ByRef command) { ControlClick, %ctrl%, %title%, %text%, %button%, %click_count%, %options%, %exclude_title%, %exclude_text% if (ErrorLevel != 0) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "Failed to click control") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "Failed to click control") } else { response := FormatNoValueResponse() } @@ -2236,8 +2166,7 @@ AHKControlClick(ByRef command) { AHKControlGetText(ByRef command) { {% block AHKControlGetText %} - global STRINGRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + ctrl := command[2] title := command[3] text := command[4] @@ -2264,9 +2193,9 @@ AHKControlGetText(ByRef command) { ControlGetText, result, %ctrl%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem getting the text") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem getting the text") } else { - response := FormatResponse(STRINGRESPONSEMESSAGE, result) + response := FormatResponse("ahk.message.StringResponseMessage", result) } DetectHiddenWindows, %current_detect_hw% SetTitleMatchMode, %current_match_mode% @@ -2276,11 +2205,9 @@ AHKControlGetText(ByRef command) { {% endblock AHKControlGetText %} } - AHKControlGetPos(ByRef command) { {% block AHKControlGetPos %} - global POSITIONRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE + ctrl := command[2] title := command[3] text := command[4] @@ -2306,10 +2233,10 @@ AHKControlGetPos(ByRef command) { ControlGetPos, x, y, w, h, %ctrl%, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem getting the text") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem getting the text") } else { result := Format("({1:i}, {2:i}, {3:i}, {4:i})", x, y, w, h) - response := FormatResponse(PositionResponseMessage, result) + response := FormatResponse("ahk.message.PositionResponseMessage", result) } DetectHiddenWindows, %current_detect_hw% @@ -2318,7 +2245,6 @@ AHKControlGetPos(ByRef command) { return response - {% endblock AHKControlGetPos %} } @@ -2355,39 +2281,34 @@ AHKControlSend(ByRef command) { {% endblock AHKControlSend %} } - - - AHKWinFromMouse(ByRef command) { {% block AHKWinFromMouse %} - global WINDOWRESPONSEMESSAGE + MouseGetPos,,, MouseWin if (MouseWin = "") { return FormatNoValueResponse() } - return FormatResponse(WINDOWRESPONSEMESSAGE, MouseWin) + return FormatResponse("ahk.message.WindowResponseMessage", MouseWin) {% endblock AHKWinFromMouse %} } - AHKWinIsAlwaysOnTop(ByRef command) { {% block AHKWinIsAlwaysOnTop %} - global BOOLEANRESPONSEMESSAGE + title := command[2] WinGet, ExStyle, ExStyle, %title% if (ExStyle = "") return FormatNoValueResponse() if (ExStyle & 0x8) ; 0x8 is WS_EX_TOPMOST. - return FormatResponse(BOOLEANRESPONSEMESSAGE, 1) + return FormatResponse("ahk.message.BooleanResponseMessage", 1) else - return FormatResponse(BOOLEANRESPONSEMESSAGE, 0) + return FormatResponse("ahk.message.BooleanResponseMessage", 0) {% endblock AHKWinIsAlwaysOnTop %} } - AHKWinMove(ByRef command) { {% block AHKWinMove %} title := command[2] @@ -2429,8 +2350,6 @@ AHKWinMove(ByRef command) { AHKWinGetPos(ByRef command) { {% block AHKWinGetPos %} - global POSITIONRESPONSEMESSAGE - global EXCEPTIONRESPONSEMESSAGE title := command[2] text := command[3] @@ -2457,10 +2376,10 @@ AHKWinGetPos(ByRef command) { WinGetPos, x, y, w, h, %title%, %text%, %extitle%, %extext% if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, "There was a problem getting the position") + response := FormatResponse("ahk.message.ExceptionResponseMessage", "There was a problem getting the position") } else { result := Format("({1:i}, {2:i}, {3:i}, {4:i})", x, y, w, h) - response := FormatResponse(PositionResponseMessage, result) + response := FormatResponse("ahk.message.PositionResponseMessage", result) } DetectHiddenWindows, %current_detect_hw% @@ -2471,23 +2390,21 @@ AHKWinGetPos(ByRef command) { {% endblock AHKWinGetPos %} } - AHKGetVolume(ByRef command) { {% block AHKGetVolume %} - global EXCEPTIONRESPONSEMESSAGE - global FLOATRESPONSEMESSAGE + device_number := command[2] try { SoundGetWaveVolume, retval, %device_number% } catch e { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("There was a problem getting the volume with device of index {} ({})", device_number, e.message)) + response := FormatResponse("ahk.message.ExceptionResponseMessage", Format("There was a problem getting the volume with device of index {} ({})", device_number, e.message)) return response } if (ErrorLevel = 1) { - response := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("There was a problem getting the volume with device of index {}", device_number)) + response := FormatResponse("ahk.message.ExceptionResponseMessage", Format("There was a problem getting the volume with device of index {}", device_number)) } else { - response := FormatResponse(FLOATRESPONSEMESSAGE, Format("{}", retval)) + response := FormatResponse("ahk.message.FloatResponseMessage", Format("{}", retval)) } return response {% endblock AHKGetVolume %} @@ -2504,14 +2421,14 @@ AHKSoundBeep(ByRef command) { AHKSoundGet(ByRef command) { {% block AHKSoundGet %} - global STRINGRESPONSEMESSAGE + device_number := command[2] component_type := command[3] control_type := command[4] SoundGet, retval, %component_type%, %control_type%, %device_number% ; TODO interpret return type - return FormatResponse(STRINGRESPONSEMESSAGE, Format("{}", retval)) + return FormatResponse("ahk.message.StringResponseMessage", Format("{}", retval)) {% endblock AHKSoundGet %} } @@ -2552,8 +2469,8 @@ CountNewlines(ByRef s) { AHKEcho(ByRef command) { {% block AHKEcho %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, command) + arg := command[2] + return FormatResponse("ahk.message.StringResponseMessage", arg) {% endblock AHKEcho %} } @@ -2582,8 +2499,8 @@ AHKShowToolTip(ByRef command) { AHKGetClipboard(ByRef command) { {% block AHKGetClipboard %} - global STRINGRESPONSEMESSAGE - return FormatResponse(STRINGRESPONSEMESSAGE, Clipboard) + + return FormatResponse("ahk.message.StringResponseMessage", Clipboard) {% endblock AHKGetClipboard %} } @@ -2612,15 +2529,14 @@ AHKSetClipboardAll(ByRef command) { } AHKClipWait(ByRef command) { - global TIMEOUTRESPONSEMESSAGE + timeout := command[2] wait_for_any_data := command[3] - ClipWait, %timeout%, %wait_for_any_data% if (ErrorLevel = 1) { - return FormatResponse(TIMEOUTRESPONSEMESSAGE, "timed out waiting for clipboard data") + return FormatResponse("ahk.message.TimeoutResponseMessage", "timed out waiting for clipboard data") } return FormatNoValueResponse() } @@ -2651,47 +2567,45 @@ AHKMenuTrayIcon(ByRef command) { } AHKGuiNew(ByRef command) { - global STRINGRESPONSEMESSAGE + options := command[2] title := command[3] Gui, New, %options%, %title% - return FormatResponse(STRINGRESPONSEMESSAGE, hwnd) + return FormatResponse("ahk.message.StringResponseMessage", hwnd) } AHKMsgBox(ByRef command) { - global TIMEOUTRESPONSEMESSAGE - global STRINGRESPONSEMESSAGE + options := command[2] title := command[3] text := command[4] timeout := command[5] MsgBox,% options, %title%, %text%, %timeout% IfMsgBox, Yes - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Yes") + ret := FormatResponse("ahk.message.StringResponseMessage", "Yes") IfMsgBox, No - ret := FormatResponse(STRINGRESPONSEMESSAGE, "No") + ret := FormatResponse("ahk.message.StringResponseMessage", "No") IfMsgBox, OK - ret := FormatResponse(STRINGRESPONSEMESSAGE, "OK") + ret := FormatResponse("ahk.message.StringResponseMessage", "OK") IfMsgBox, Cancel - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Cancel") + ret := FormatResponse("ahk.message.StringResponseMessage", "Cancel") IfMsgBox, Abort - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Abort") + ret := FormatResponse("ahk.message.StringResponseMessage", "Abort") IfMsgBox, Ignore - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Ignore") + ret := FormatResponse("ahk.message.StringResponseMessage", "Ignore") IfMsgBox, Retry - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Retry") + ret := FormatResponse("ahk.message.StringResponseMessage", "Retry") IfMsgBox, Continue - ret := FormatResponse(STRINGRESPONSEMESSAGE, "Continue") + ret := FormatResponse("ahk.message.StringResponseMessage", "Continue") IfMsgBox, TryAgain - ret := FormatResponse(STRINGRESPONSEMESSAGE, "TryAgain") + ret := FormatResponse("ahk.message.StringResponseMessage", "TryAgain") IfMsgBox, Timeout - ret := FormatResponse(TIMEOUTRESPONSEMESSAGE, "MsgBox timed out") + ret := FormatResponse("ahk.message.TimeoutResponseMessage", "MsgBox timed out") return ret } AHKInputBox(ByRef command) { - global STRINGRESPONSEMESSAGE - global TIMEOUTRESPONSEMESSAGE + title := command[2] prompt := command[3] hide := command[4] @@ -2705,17 +2619,17 @@ AHKInputBox(ByRef command) { InputBox, output, %title%, %prompt%, %hide%, %width%, %height%, %x%, %y%, %locale%, %timeout%, %default% if (ErrorLevel = 2) { - ret := FormatResponse(TIMEOUTRESPONSEMESSAGE, "Input box timed out") + ret := FormatResponse("ahk.message.TimeoutResponseMessage", "Input box timed out") } else if (ErrorLevel = 1) { ret := FormatNoValueResponse() } else { - ret := FormatResponse(STRINGRESPONSEMESSAGE, output) + ret := FormatResponse("ahk.message.StringResponseMessage", output) } return ret } AHKFileSelectFile(byRef command) { - global STRINGRESPONSEMESSAGE + options := command[2] root := command[3] title := command[4] @@ -2724,13 +2638,13 @@ AHKFileSelectFile(byRef command) { if (ErrorLevel = 1) { ret := FormatNoValueResponse() } else { - ret := FormatResponse(STRINGRESPONSEMESSAGE, output) + ret := FormatResponse("ahk.message.StringResponseMessage", output) } return ret } AHKFileSelectFolder(byRef command) { - global STRINGRESPONSEMESSAGE + starting_folder := command[2] options := command[3] prompt := command[4] @@ -2740,7 +2654,7 @@ AHKFileSelectFolder(byRef command) { if (ErrorLevel = 1) { ret := FormatNoValueResponse() } else { - ret := FormatResponse(STRINGRESPONSEMESSAGE, output) + ret := FormatResponse("ahk.message.StringResponseMessage", output) } return ret } @@ -2768,7 +2682,6 @@ b64decode(ByRef pszString) { pdwSkip := 0 ; We don't use any headers or preamble, so this is zero pdwFlags := 0 ; We don't need this, so make it null - ; The first call calculates the required size. The result is written to pbBinary success := DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &pszString, "UInt", cchString, "UInt", dwFlags, "UInt", getsize, "UIntP", buff_size, "Int", pdwSkip, "Int", pdwFlags ) if (success = 0) { @@ -2796,7 +2709,6 @@ b64encode(ByRef data) { ; [out, optional] LPSTR pszString: A pointer to the string, or null (0) to calculate size ; [in, out] DWORD *pcchString: A pointer to a DWORD variable that contains the size, in TCHARs, of the pszString buffer - cbBinary := StrLen(data) * (A_IsUnicode ? 2 : 1) if (cbBinary = 0) { return "" @@ -2810,7 +2722,6 @@ b64encode(ByRef data) { throw Exception(msg, -1) } - VarSetCapacity(ret, buff_size * (A_IsUnicode ? 2 : 1)) ; Now we do the conversion to base64 and rteturn the string @@ -2823,7 +2734,6 @@ b64encode(ByRef data) { return ret } - ; End of included content CommandArrayFromQuery(ByRef text) { @@ -2865,14 +2775,14 @@ Loop { } catch e { {% block function_error_handle %} message := Format("Error occurred in {}. The error message was: {}", e.What, e.message) - pyresp := FormatResponse(EXCEPTIONRESPONSEMESSAGE, message) + pyresp := FormatResponse("ahk.message.ExceptionResponseMessage", message) {% endblock function_error_handle %} } {% block send_response %} if (pyresp) { FileAppend, %pyresp%, *, UTF-8 } else { - msg := FormatResponse(EXCEPTIONRESPONSEMESSAGE, Format("Unknown Error when calling {}", func)) + msg := FormatResponse("ahk.message.ExceptionResponseMessage", Format("Unknown Error when calling {}", func)) FileAppend, %msg%, *, UTF-8 } {% endblock send_response %} From ae954efc4bc677f5753160042078a923b60b4f05 Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Thu, 24 Aug 2023 19:01:20 -0700 Subject: [PATCH 6/9] use Critical on daemon thread --- ahk/_constants.py | 2 ++ ahk/templates/daemon.ahk | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ahk/_constants.py b/ahk/_constants.py index 39b84fc..baea312 100644 --- a/ahk/_constants.py +++ b/ahk/_constants.py @@ -27,6 +27,8 @@ {% endblock user_directives %} {% endblock directives %} +Critical, 100 + {% block message_types %} MESSAGE_TYPES := Object({% for tom, msg_class in message_registry.items() %}"{{ msg_class.fqn() }}", "{{ tom.decode('utf-8') }}"{% if not loop.last %}, {% endif %}{% endfor %}) {% endblock message_types %} diff --git a/ahk/templates/daemon.ahk b/ahk/templates/daemon.ahk index 3daf2c7..32f136c 100644 --- a/ahk/templates/daemon.ahk +++ b/ahk/templates/daemon.ahk @@ -24,6 +24,8 @@ {% endblock user_directives %} {% endblock directives %} +Critical, 100 + {% block message_types %} MESSAGE_TYPES := Object({% for tom, msg_class in message_registry.items() %}"{{ msg_class.fqn() }}", "{{ tom.decode('utf-8') }}"{% if not loop.last %}, {% endif %}{% endfor %}) {% endblock message_types %} From 52c18774c57fb902a90f158ce3798679bab9268b Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Thu, 24 Aug 2023 21:08:49 -0700 Subject: [PATCH 7/9] extension documentation --- ahk/_async/engine.py | 6 + ahk/_sync/engine.py | 6 + docs/api/index.rst | 1 + docs/api/message.rst | 7 ++ docs/extending.rst | 256 +++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 6 files changed, 277 insertions(+) create mode 100644 docs/api/message.rst create mode 100644 docs/extending.rst diff --git a/ahk/_async/engine.py b/ahk/_async/engine.py index c7937d3..7d2e51c 100644 --- a/ahk/_async/engine.py +++ b/ahk/_async/engine.py @@ -204,6 +204,12 @@ def add_hotkey( warnings.warn(warning.message, warning.category, stacklevel=2) return None + async def function_call(self, function_name: str, args: list[str], blocking: bool = True) -> Any: + """ + Call an AHK function defined in the daemon script. This method is intended for use by extension authors. + """ + return await self._transport.function_call(function_name, args, blocking=blocking, engine=self) # type: ignore[call-overload] + def add_hotstring( self, trigger: str, diff --git a/ahk/_sync/engine.py b/ahk/_sync/engine.py index 8f93d06..2d7cfd6 100644 --- a/ahk/_sync/engine.py +++ b/ahk/_sync/engine.py @@ -198,6 +198,12 @@ def add_hotkey( warnings.warn(warning.message, warning.category, stacklevel=2) return None + def function_call(self, function_name: str, args: list[str], blocking: bool = True) -> Any: + """ + Call an AHK function defined in the daemon script. This method is intended for use by extension authors. + """ + return self._transport.function_call(function_name, args, blocking=blocking, engine=self) # type: ignore[call-overload] + def add_hotstring( self, trigger: str, diff --git a/docs/api/index.rst b/docs/api/index.rst index 5563455..4a2b461 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -14,3 +14,4 @@ about the programming interface. This is largely auto-generated documentation. async methods directives + message diff --git a/docs/api/message.rst b/docs/api/message.rst new file mode 100644 index 0000000..d1afe0f --- /dev/null +++ b/docs/api/message.rst @@ -0,0 +1,7 @@ +Message +======= + + +.. automodule:: ahk.message + :members: + :undoc-members: diff --git a/docs/extending.rst b/docs/extending.rst new file mode 100644 index 0000000..26579af --- /dev/null +++ b/docs/extending.rst @@ -0,0 +1,256 @@ +Extending AHK +============= + +.. attention:: + The extension feature is in early stages of development and may change at any time, including breaking changes in minor version releases. + +You can extend AHK to add more functionality. This is particularly useful for those who may want to +contribute their own solutions into the ecosystem that others can use. + +For users of an extension, their interface will typically look like this: + +1. Install the extension (e.g., ``pip install ...``) +2. import the extension(s) and enable extensions when instantiating the ``AHK`` class + +.. code-block:: + + from my_great_extension import the_extension + from ahk import AHK + ahk = AHK(extensions='auto') # use all available/imported extensions + ahk.my_great_method('foo', 'bar', 'baz') # new methods are available from the extension! + + +This document will describe how you can create your own extensions and also cover some basics of packaging and +distributing an extension for ``ahk`` on PyPI. + + +Background +---------- + +First, a little background is necessary into the inner mechanisms of how ``ahk`` does what it does. It is important for +extension authors to understand these key points: + +- Python calls AHK functions by name and can pass any number of strings as parameters. +- Functions written in AHK (v1) accept exactly one argument (an array of zero or more strings) and must return responses in a specific message format (we'll discuss these specifics later) +- The message returned from AHK to Python indicates the type of the return value so Python can parse the response message into an appropriate Python type. There are several predefined message types available in the :py:mod:`ahk.message` module. Extension authors may also create their own message types (discussed later). + + + +Writing an extension +-------------------- + +The basics of writing an extension requires two key components: + + +- A function written in AHK (v1) that conforms to the required spec (accepts one argument of an array of strings and returns a formatted message). +- A python function that accepts an instance of `AHK` (or `AsyncAHK for `async` functions) as its first parameter (think of it like a method of the `AHK` class). It may also accept any additional parameters. + + +Example +^^^^^^^ + +This simple example extension will provide a new method on the ``AHK`` class called ``simple_math``. This new method +accepts three arguments: two operands (``lhs`` and ``rhs``) and an operator (``+`` or ``*``). + +When complete, the interface will look something like this: + +.. code-block:: + + ahk = AHK(extensions='auto') + print(ahk.simple_math(2, 2, '+')) # 4 + + +Let's begin writing the extension. + +First, we'll start with the AutoHotkey code. This will be an AHK (v1) function that accepts a single argument, which +is an array containing the arguments of the function passed by Python. These start at index 2. + +Ultimately, the function will perform some operation utilizing these inputs and will return a formatted response +(using the ``FormatResponse`` function which is already defined for you. It accepts two arguments: the messaage type name +and the raw payload. + +.. code-block:: + + + SimpleMath(ByRef command) { + + ; `command` is an array with passed arguments, starting at index 2 + lhs := command[2] + rhs := command[3] + operator := command[4] + + if (operator = "+") { + result := (lhs + rhs) + } else if (operator = "*") { + result := (lhs * rhs) + } else { ; invalid operator argument + return FormatResponse("ahk.message.ExceptionResponseMessage", Format("Invalid operator: {}", operator)) + } + + return FormatResponse("ahk.message.IntegerResponseMessage", result) + } + + +Note that the ``FormatResponse`` function is already implemented for you! + + +Next, we'll create the Python components of our extension: a Python function and the extension itself. The extension +itself is an instance of the ``Extension`` class and it accepts an argument ``script_text`` which will be a string +containing the AutoHotkey code we just wrote above. + + +.. code-block:: + + from ahk import AHK + from ahk.extensions import Extension + from typing import Literal + + script_text = r'''\ + ; a string of your AHK script + ; Omitted here for brevity -- copy/paste from the previous code block + ''' + simple_math_extension = Extension(script_text=script_text) + + @simple_meth_extension.register # register the method for the extension + def simple_math(ahk: AHK, lhs: int, rhs: int, operator: Literal['+', '*']) -> int: + assert isinstance(lhs, int) + assert isinstance(rhs, int) + # assert operator in ('+', '*') # we'll leave this out so we can demo raising exceptions from AHK + args = [str(lhs), str(rhs), operator] # all args must be strings + result = ahk.function_call('SimpleMath', args, blocking=True) + return result + + +After the extension is created, it can be used automatically! + +.. code-block:: + + # ... above code omitted for brevity + ahk = AHK(extensions='auto') + + result = ahk.simple_math(2, 4, operator='+') + print('2 + 4 =', result) + assert result == 6 + + result = ahk.simple_math(2, 4, operator='*') + print('2 * 4 =', result) + assert result == 8 + + # this will raise our custom exception from our AHK code + try: + ahk.simple_math(0, 0, operator='invalid') + except Exception as e: + print('An exception was raised. Exception message was:', e) + +If you use this example code, it should output something like this: :: + + 2 + 4 = 6 + 2 * 4 = 8 + An exception was raised. Exception message was: Invalid operator: % + + + + +Includes +^^^^^^^^ + +In addition to supplying AutoHotkey extension code via ``script_text``, you may also do this using includes. + +.. code-block:: + + from ahk.extensions import Extension + my_extension = Extension(includes=['myscript.ahk']) # equivalent to "#Include myscript.ahk" + + +Available Message Types +^^^^^^^^^^^^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + + * - Message type + - Python return type + - Payload description + * - :py:class:`ahk.message.TupleResponseMessage` + - A ``tuple`` object containing any number of literal types (``Tuple[Any, ...]``) + - A string representing a tuple literal (i.e. usable with ``ast.literal_eval``) + * - :py:class:`ahk.message.CoordinateResponseMessage` + - A tuple containing two integers (``Tuple[int, int]``) + - A string representing the tuple literal + * - :py:class:`ahk.message.IntegerResponseMessage` + - An integer (``int``) + - A string literal representing an integer + * - :py:class:`ahk.message.BooleanResponseMessage` + - A boolean (``bool``) + - A string literal of either ``0`` or ``1`` + * - :py:class:`ahk.message.StringResponseMessage` + - A string (``str``) + - Any string + * - :py:class:`ahk.message.WindowListResponseMessage` + - A list of :py:class:`~ahk._sync.window.Window` (or :py:class:`~ahk._async.window.AsyncWindow`) objects + - A string containing a comma-delimited list of window IDs + * - :py:class:`ahk.message.NoValueResponseMessage` + - NoneType (``None``) + - A sentinel value (use ``FormatNoValueResponse()`` in AHK for returning this message) + * - :py:class:`ahk.message.ExceptionResponseMessage` + - raises an Exception. + - A string with the exception message + * - :py:class:`ahk.message.WindowControlListResponseMessage` + - A list of :py:class:`~ahk._sync.window.Control` (or :py:class:`~ahk._async.window.AsyncControl`) objects + - A string literal representing a tuple containing the window hwnd and a list of tuples each containing the control hwnd and class for each control + * - :py:class:`ahk.message.WindowResponseMessage` + - A :py:class:`~ahk._sync.Window` (or ``AsyncWindow``) object + - A string containing the ID of the window + * - :py:class:`ahk.message.PositionResponseMessage` + - A ``Postion`` namedtuple object, consisting of 4 integers with named attributes ``x``, ``y``, ``width``, and ``height`` + - A string representing the tuple literal + * - :py:class:`ahk.message.FloatResponseMessage` + - ``float`` + - A string literal representation of a float + * - :py:class:`ahk.message.TimeoutResponseMessage` + - raises a ``TimeoutException`` + - A string containing the exception message + * - :py:class:`ahk.message.B64BinaryResponseMessage` + - ``bytes`` object + - A string containing base64-encoded binary data + + +Returning custom types (make your own message type) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can design your extension functions to ultimately return different types by implementing your own message class. + +To do this, subclass :py:class:`ahk.message.ResponseMessage` (or any of its other subclasses) and implement the ``unpack`` method. + +For example, suppose you want your method to return a datetime object, you might do something like this: + +.. code-block:: + + import datetime + from ahk.message import IntegerResponseMessage + class DatetimeResponseMessage(IntegerResponseMessage): + def unpack(self) -> datetime.datetime: + val = super().unpack() # get the integer timestamp + return datetime.datetime.fromtimestamp(val) + +In AHK code, you can reference custom response messages by the their fully qualified name, including the namespace. +(if you're not sure what this means, you can see this value by calling ``DateTimeResponseMessage.fqn()``) + + + +Packaging +^^^^^^^^^ + +Coming soon. + +Notes +^^^^^ + +- AHK functions MUST always return a message. Failing to return a message will result in an exception being raised. If the function should return nothing, use ``return FormatNoValueResponse()`` which will translate to ``None`` in Python. +- You cannot define hotkeys, hotstrings, or write any AutoHotkey code that would cause the end of autoexecution + + +Extending with jinja +^^^^^^^^^^^^^^^^^^^^ + +Coming soon. diff --git a/docs/index.rst b/docs/index.rst index 736ce73..90e24c2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,6 +17,7 @@ ahk Python wrapper documentation quickstart README api/index + extending From 8327cb0808d110b5c87a914518f9cf5a03b6f6ca Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Thu, 24 Aug 2023 23:48:52 -0700 Subject: [PATCH 8/9] notes --- docs/extending.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/extending.rst b/docs/extending.rst index 26579af..ed3badb 100644 --- a/docs/extending.rst +++ b/docs/extending.rst @@ -236,6 +236,13 @@ For example, suppose you want your method to return a datetime object, you might In AHK code, you can reference custom response messages by the their fully qualified name, including the namespace. (if you're not sure what this means, you can see this value by calling ``DateTimeResponseMessage.fqn()``) +Notes +^^^^^ + +- AHK functions MUST always return a message. Failing to return a message will result in an exception being raised. If the function should return nothing, use ``return FormatNoValueResponse()`` which will translate to ``None`` in Python. +- You cannot define hotkeys, hotstrings, or write any AutoHotkey code that would cause the end of autoexecution +- Extensions must be imported *before* instantiating the ``AHK`` instance +- Although extensions can be declared explicitly, using ``extensions='auto'`` is the recommended method for enabling extensions Packaging @@ -243,12 +250,6 @@ Packaging Coming soon. -Notes -^^^^^ - -- AHK functions MUST always return a message. Failing to return a message will result in an exception being raised. If the function should return nothing, use ``return FormatNoValueResponse()`` which will translate to ``None`` in Python. -- You cannot define hotkeys, hotstrings, or write any AutoHotkey code that would cause the end of autoexecution - Extending with jinja ^^^^^^^^^^^^^^^^^^^^ From be14d1c6620d46022c7960417ba4f9f6dbef38ad Mon Sep 17 00:00:00 2001 From: Spencer Phillip Young Date: Fri, 25 Aug 2023 00:26:18 -0700 Subject: [PATCH 9/9] update tests --- tests/_async/test_extensions.py | 5 ++--- tests/_sync/test_extensions.py | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/_async/test_extensions.py b/tests/_async/test_extensions.py index 95651dc..1842a2e 100644 --- a/tests/_async/test_extensions.py +++ b/tests/_async/test_extensions.py @@ -13,9 +13,8 @@ ext_text = '''\ AHKDoSomething(ByRef command) { - global STRINGRESPONSEMESSAGE arg := command[2] - return FormatResponse(STRINGRESPONSEMESSAGE, Format("test{}", arg)) + return FormatResponse("ahk.message.StringResponseMessage", Format("test{}", arg)) } ''' @@ -24,7 +23,7 @@ @async_extension.register async def do_something(ahk, arg: str) -> str: - res = await ahk._transport.function_call('AHKDoSomething', [arg]) + res = await ahk.function_call('AHKDoSomething', [arg]) return res diff --git a/tests/_sync/test_extensions.py b/tests/_sync/test_extensions.py index c78d392..8eadcb2 100644 --- a/tests/_sync/test_extensions.py +++ b/tests/_sync/test_extensions.py @@ -12,9 +12,8 @@ ext_text = '''\ AHKDoSomething(ByRef command) { - global STRINGRESPONSEMESSAGE arg := command[2] - return FormatResponse(STRINGRESPONSEMESSAGE, Format("test{}", arg)) + return FormatResponse("ahk.message.StringResponseMessage", Format("test{}", arg)) } ''' @@ -23,7 +22,7 @@ @async_extension.register def do_something(ahk, arg: str) -> str: - res = ahk._transport.function_call('AHKDoSomething', [arg]) + res = ahk.function_call('AHKDoSomething', [arg]) return res