Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gui methods #221

Merged
merged 7 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 16 additions & 1 deletion ahk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,23 @@
from ._sync import AHK
from ._sync import Control
from ._sync import Window
from ._utils import MsgBoxButtons
from ._utils import MsgBoxDefaultButton
from ._utils import MsgBoxIcon
from ._utils import MsgBoxModality

__all__ = ['AHK', 'Window', 'AsyncWindow', 'AsyncAHK', 'Control', 'AsyncControl']
__all__ = [
'AHK',
'Window',
'AsyncWindow',
'AsyncAHK',
'Control',
'AsyncControl',
'MsgBoxButtons',
'MsgBoxDefaultButton',
'MsgBoxIcon',
'MsgBoxModality',
]

_global_instance: Optional[AHK] = None

Expand Down
185 changes: 185 additions & 0 deletions ahk/_async/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@

from .._hotkey import Hotkey
from .._hotkey import Hotstring
from .._utils import MsgBoxButtons
from .._utils import MsgBoxDefaultButton
from .._utils import MsgBoxIcon
from .._utils import MsgBoxModality
from .._utils import MsgBoxOtherOptions
from .._utils import type_escape
from ..directives import Directive

Expand All @@ -35,8 +40,11 @@
from .transport import AsyncTransport
from .window import AsyncControl
from .window import AsyncWindow

# from .window import AsyncGui
from ahk.message import Position


async_sleep = asyncio.sleep # unasync: remove
sleep = time.sleep

Expand Down Expand Up @@ -3486,6 +3494,183 @@ async def reg_read(
args.append(value_name)
return await self._transport.function_call('AHKRegRead', args, blocking=blocking)

# fmt: off
@overload
async def msg_box(self, text: str = '', title: str = 'Message', buttons: MsgBoxButtons = MsgBoxButtons.OK, icon: Optional[MsgBoxIcon] = None, default_button: Optional[MsgBoxDefaultButton] = None, modality: Optional[MsgBoxModality] = None, help_button: bool = False, text_right_justified: bool = False, right_to_left_reading: bool = False, timeout: Optional[int] = None) -> str: ...
@overload
async def msg_box(self, text: str = '', title: str = 'Message', buttons: MsgBoxButtons = MsgBoxButtons.OK, icon: Optional[MsgBoxIcon] = None, default_button: Optional[MsgBoxDefaultButton] = None, modality: Optional[MsgBoxModality] = None, help_button: bool = False, text_right_justified: bool = False, right_to_left_reading: bool = False, timeout: Optional[int] = None, *, blocking: Literal[False]) -> AsyncFutureResult[str]: ...
@overload
async def msg_box(self, text: str = '', title: str = 'Message', buttons: MsgBoxButtons = MsgBoxButtons.OK, icon: Optional[MsgBoxIcon] = None, default_button: Optional[MsgBoxDefaultButton] = None, modality: Optional[MsgBoxModality] = None, help_button: bool = False, text_right_justified: bool = False, right_to_left_reading: bool = False, timeout: Optional[int] = None, *, blocking: Literal[True]) -> str: ...
@overload
async def msg_box(self, text: str = '', title: str = 'Message', buttons: MsgBoxButtons = MsgBoxButtons.OK, icon: Optional[MsgBoxIcon] = None, default_button: Optional[MsgBoxDefaultButton] = None, modality: Optional[MsgBoxModality] = None, help_button: bool = False, text_right_justified: bool = False, right_to_left_reading: bool = False, timeout: Optional[int] = None, *, blocking: bool = True) -> Union[str, AsyncFutureResult[str]]: ...
# fmt: on
async def msg_box(
self,
text: str = '',
title: str = 'Message',
buttons: MsgBoxButtons = MsgBoxButtons.OK,
icon: Optional[MsgBoxIcon] = None,
default_button: Optional[MsgBoxDefaultButton] = None,
modality: Optional[MsgBoxModality] = None,
help_button: bool = False,
text_right_justified: bool = False,
right_to_left_reading: bool = False,
timeout: Optional[int] = None,
*,
blocking: bool = True,
) -> Union[str, AsyncFutureResult[str]]:
options: int = int(buttons)
for opt in (icon, default_button, modality):
if opt is not None:
options += opt
if help_button:
options += MsgBoxOtherOptions.HELP_BUTTON
if text_right_justified:
options += MsgBoxOtherOptions.TEXT_RIGHT_JUSTIFIED
if right_to_left_reading:
options += MsgBoxOtherOptions.RIGHT_TO_LEFT_READING_ORDER

args = [str(options), title, text]
if timeout is not None:
args.append(str(timeout))
return await self._transport.function_call('AHKMsgBox', args, blocking=blocking)

# fmt: off
@overload
async def input_box(self, prompt: str = '', title: str = 'Input', default: str = '', hide: bool = False, width: Optional[int] = None, height: Optional[int] = None, x: Optional[int] = None, y: Optional[int] = None, locale: bool = True, timeout: Optional[int] = None) -> Union[None, str]: ...
@overload
async def input_box(self, prompt: str = '', title: str = 'Input', default: str = '', hide: bool = False, width: Optional[int] = None, height: Optional[int] = None, x: Optional[int] = None, y: Optional[int] = None, locale: bool = True, timeout: Optional[int] = None, *, blocking: Literal[False]) -> Union[AsyncFutureResult[str], AsyncFutureResult[None]]: ...
@overload
async def input_box(self, prompt: str = '', title: str = 'Input', default: str = '', hide: bool = False, width: Optional[int] = None, height: Optional[int] = None, x: Optional[int] = None, y: Optional[int] = None, locale: bool = True, timeout: Optional[int] = None, *, blocking: Literal[True]) -> Union[str, None]: ...
@overload
async def input_box(self, prompt: str = '', title: str = 'Input', default: str = '', hide: bool = False, width: Optional[int] = None, height: Optional[int] = None, x: Optional[int] = None, y: Optional[int] = None, locale: bool = True, timeout: Optional[int] = None, *, blocking: bool = True) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]: ...
# fmt: on
async def input_box(
self,
prompt: str = '',
title: str = 'Input',
default: str = '',
hide: bool = False,
width: Optional[int] = None,
height: Optional[int] = None,
x: Optional[int] = None,
y: Optional[int] = None,
locale: bool = True,
timeout: Optional[int] = None,
*,
blocking: bool = True,
) -> Union[None, str, AsyncFutureResult[str], AsyncFutureResult[None]]:
"""
Like AHK's ``InputBox``

If the user presses Cancel or closes the box, ``None`` is returned.
Otherwise, the user's input is returned.
Raises a ``TimeoutError`` if a timeout is specified and expires.
"""
args = [title, prompt]
if hide:
args.append('hide')
else:
args.append('')
for opt in (width, height, x, y):
if opt is not None:
args.append(str(opt))
else:
args.append('')
if locale:
args.append('Locale')
else:
args.append('')
if timeout is not None:
args.append(str(timeout))
else:
args.append('')
args.append(default)
return await self._transport.function_call('AHKInputBox', args, blocking=blocking)

# fmt: off
@overload
async def file_select_box(self, title: str = 'Select File', multi: bool = False, root: str = '', filter: str = '', save_button: bool = False, file_must_exist: bool = False, path_must_exist: bool = False, prompt_create_new_file: bool = False, prompt_override_file: bool = False, follow_shortcuts: bool = True) -> Union[None, str]: ...
@overload
async def file_select_box(self, title: str = 'Select File', multi: bool = False, root: str = '', filter: str = '', save_button: bool = False, file_must_exist: bool = False, path_must_exist: bool = False, prompt_create_new_file: bool = False, prompt_override_file: bool = False, follow_shortcuts: bool = True, *, blocking: Literal[False]) -> Union[AsyncFutureResult[str], AsyncFutureResult[None]]: ...
@overload
async def file_select_box(self, title: str = 'Select File', multi: bool = False, root: str = '', filter: str = '', save_button: bool = False, file_must_exist: bool = False, path_must_exist: bool = False, prompt_create_new_file: bool = False, prompt_override_file: bool = False, follow_shortcuts: bool = True, *, blocking: Literal[True]) -> Union[str, None]: ...
@overload
async def file_select_box(self, title: str = 'Select File', multi: bool = False, root: str = '', filter: str = '', save_button: bool = False, file_must_exist: bool = False, path_must_exist: bool = False, prompt_create_new_file: bool = False, prompt_override_file: bool = False, follow_shortcuts: bool = True, *, blocking: bool = True) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]: ...
# fmt: on
async def file_select_box(
self,
title: str = 'Select File',
multi: bool = False,
root: str = '',
filter: str = '',
save_button: bool = False,
file_must_exist: bool = False,
path_must_exist: bool = False,
prompt_create_new_file: bool = False,
prompt_override_file: bool = False,
follow_shortcuts: bool = True,
*,
blocking: bool = True,
) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]:
opts = 0
if file_must_exist:
opts += 1
if path_must_exist:
opts += 2
if prompt_create_new_file:
opts += 8
if prompt_override_file:
opts += 8
if not follow_shortcuts:
opts += 32
options = ''
if multi:
options += 'M'
if save_button:
options += 'S'
if opts:
options += str(opts)
args = [options, root, title, filter]
return await self._transport.function_call('AHKFileSelectFile', args, blocking=blocking)

# fmt: off
@overload
async def folder_select_box(self, prompt: str = 'Select Folder', root: str = '', chroot: bool = False, enable_new_directories: bool = True, edit_field: bool = False, new_dialog_style: bool = False) -> Union[None, str]: ...
@overload
async def folder_select_box(self, prompt: str = 'Select Folder', root: str = '', chroot: bool = False, enable_new_directories: bool = True, edit_field: bool = False, new_dialog_style: bool = False, *, blocking: Literal[False]) -> Union[AsyncFutureResult[str], AsyncFutureResult[None]]: ...
@overload
async def folder_select_box(self, prompt: str = 'Select Folder', root: str = '', chroot: bool = False, enable_new_directories: bool = True, edit_field: bool = False, new_dialog_style: bool = False, *, blocking: Literal[True]) -> Union[str, None]: ...
@overload
async def folder_select_box(self, prompt: str = 'Select Folder', root: str = '', chroot: bool = False, enable_new_directories: bool = True, edit_field: bool = False, new_dialog_style: bool = False, *, blocking: bool = True) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]: ...
# fmt: on
async def folder_select_box(
self,
prompt: str = 'Select Folder',
root: str = '',
chroot: bool = False,
enable_new_directories: bool = True,
edit_field: bool = False,
new_dialog_style: bool = False,
*,
blocking: bool = True,
) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]:
if not chroot:
starting_folder = '*'
else:
starting_folder = ''
starting_folder += root
if enable_new_directories:
opts = 1
else:
opts = 0
if edit_field:
opts += 2
if new_dialog_style:
opts += 4
args = [starting_folder, str(opts), prompt]
return await self._transport.function_call('AHKFileSelectFolder', args, blocking=blocking)

async def block_forever(self) -> NoReturn:
"""
Blocks (sleeps) forever. Utility method to prevent script from exiting.
Expand Down
16 changes: 15 additions & 1 deletion ahk/_async/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,24 @@ def result(self, timeout: Optional[float] = None) -> T_SyncFuture:
'AHKControlGetPos',
'AHKControlGetText',
'AHKControlSend',
'AHKFileSelectFile',
'AHKFileSelectFolder',
'AHKGetClipboard',
'AHKGetClipboardAll',
'AHKGetCoordMode',
'AHKGetSendLevel',
'AHKGetTitleMatchMode',
'AHKGetTitleMatchSpeed',
'AHKGetVolume',
'AHKGuiNew',
'AHKImageSearch',
'AHKInputBox',
'AHKKeyState',
'AHKKeyWait',
'AHKMenuTrayIcon',
'AHKMenuTrayShow',
'AHKMenuTrayTip',
'AHKMsgBox',
'AHKMouseClickDrag',
'AHKMouseGetPos',
'AHKMouseMove',
Expand Down Expand Up @@ -591,7 +596,16 @@ async def function_call(self, function_name: Literal['AHKMenuTrayTip'], args: Op
async def function_call(self, function_name: Literal['AHKMenuTrayIcon'], args: Optional[List[str]] = None, *, blocking: bool = True) -> Union[None, AsyncFutureResult[None]]: ...
@overload
async def function_call(self, function_name: Literal['AHKMenuTrayShow'], args: Optional[List[str]] = None, *, blocking: bool = True) -> Union[None, AsyncFutureResult[None]]: ...

@overload
async def function_call(self, function_name: Literal['AHKGuiNew'], args: List[str], *, engine: AsyncAHK) -> str: ...
@overload
async def function_call(self, function_name: Literal['AHKMsgBox'], args: Optional[List[str]] = None, *, blocking: bool = True) -> Union[str, AsyncFutureResult[str]]: ...
@overload
async def function_call(self, function_name: Literal['AHKInputBox'], args: Optional[List[str]] = None, *, blocking: bool = True) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]: ...
@overload
async def function_call(self, function_name: Literal['AHKFileSelectFile'], args: Optional[List[str]] = None, *, blocking: bool = True) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]: ...
@overload
async def function_call(self, function_name: Literal['AHKFileSelectFolder'], args: Optional[List[str]] = None, *, blocking: bool = True) -> Union[str, None, AsyncFutureResult[str], AsyncFutureResult[None]]: ...
# fmt: on

async def function_call(
Expand Down
95 changes: 95 additions & 0 deletions ahk/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2644,6 +2644,101 @@
return FormatNoValueResponse()
}

AHKGuiNew(ByRef command) {
global STRINGRESPONSEMESSAGE
options := command[2]
title := command[3]
Gui, New, %options%, %title%
return FormatResponse(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")
IfMsgBox, No
ret := FormatResponse(STRINGRESPONSEMESSAGE, "No")
IfMsgBox, OK
ret := FormatResponse(STRINGRESPONSEMESSAGE, "OK")
IfMsgBox, Cancel
ret := FormatResponse(STRINGRESPONSEMESSAGE, "Cancel")
IfMsgBox, Abort
ret := FormatResponse(STRINGRESPONSEMESSAGE, "Abort")
IfMsgBox, Ignore
ret := FormatResponse(STRINGRESPONSEMESSAGE, "Ignore")
IfMsgBox, Retry
ret := FormatResponse(STRINGRESPONSEMESSAGE, "Retry")
IfMsgBox, Continue
ret := FormatResponse(STRINGRESPONSEMESSAGE, "Continue")
IfMsgBox, TryAgain
ret := FormatResponse(STRINGRESPONSEMESSAGE, "TryAgain")
IfMsgBox, Timeout
ret := FormatResponse(TIMEOUTRESPONSEMESSAGE, "MsgBox timed out")
return ret
}

AHKInputBox(ByRef command) {
global STRINGRESPONSEMESSAGE
global TIMEOUTRESPONSEMESSAGE
title := command[2]
prompt := command[3]
hide := command[4]
width := command[5]
height := command[6]
x := command[7]
y := command[8]
locale := command[9]
timeout := command[10]
default := command[11]

InputBox, output, %title%, %prompt%, %hide%, %width%, %height%, %x%, %y%, %locale%, %timeout%, %default%
if (ErrorLevel = 2) {
ret := FormatResponse(TIMEOUTRESPONSEMESSAGE, "Input box timed out")
} else if (ErrorLevel = 1) {
ret := FormatNoValueResponse()
} else {
ret := FormatResponse(STRINGRESPONSEMESSAGE, output)
}
return ret
}

AHKFileSelectFile(byRef command) {
global STRINGRESPONSEMESSAGE
options := command[2]
root := command[3]
title := command[4]
filter := command[5]
FileSelectFile, output, %options%, %root%, %title%, %filter%
if (ErrorLevel = 1) {
ret := FormatNoValueResponse()
} else {
ret := FormatResponse(STRINGRESPONSEMESSAGE, output)
}
return ret
}

AHKFileSelectFolder(byRef command) {
global STRINGRESPONSEMESSAGE
starting_folder := command[2]
options := command[3]
prompt := command[4]

FileSelectFolder, output, %starting_folder%, %options%, %prompt%

if (ErrorLevel = 1) {
ret := FormatNoValueResponse()
} else {
ret := FormatResponse(STRINGRESPONSEMESSAGE, output)
}
return ret
}

b64decode(ByRef pszString) {
; TODO load DLL globally for performance
; REF: https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptstringtobinaryw
Expand Down