Skip to content

Commit

Permalink
Merge 4693f77 into c17f80f
Browse files Browse the repository at this point in the history
  • Loading branch information
spyoungtech committed Jun 15, 2022
2 parents c17f80f + 4693f77 commit af37364
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 20 deletions.
14 changes: 14 additions & 0 deletions ahk/templates/_daemon.ahk
Expand Up @@ -504,6 +504,20 @@ AHKWinGetPos(ByRef command) {
return s
}

AHKWinWait(ByRef command) {
title := command[2]
text := command[3]
timeout := command[4]
extitle := command[5]
extext := command[6]
WinWait,%title%,%text%,%timeout%,%extitle%,%extext%
if !ErrorLevel
{
WinGet, output, ID
return output
}
}

CountNewlines(ByRef s) {
newline := "`n"
StringReplace, s, s, %newline%, %newline%, UseErrorLevel
Expand Down
14 changes: 14 additions & 0 deletions ahk/templates/daemon.ahk
Expand Up @@ -512,6 +512,20 @@ AHKWinGetPos(ByRef command) {
return s
}

AHKWinWait(ByRef command) {
title := command[2]
text := command[3]
timeout := command[4]
extitle := command[5]
extext := command[6]
WinWait,%title%,%text%,%timeout%,%extitle%,%extext%
if !ErrorLevel
{
WinGet, output, ID
return output
}
}

CountNewlines(ByRef s) {
newline := "`n"
StringReplace, s, s, %newline%, %newline%, UseErrorLevel
Expand Down
1 change: 1 addition & 0 deletions ahk/templates/daemon/win_wait.ahk
@@ -0,0 +1 @@
AHKWinWait,{{title}},{{text}},{{timeout}},{{exclude_title}},{{exclude_text}}
9 changes: 9 additions & 0 deletions ahk/templates/window/win_wait.ahk
@@ -0,0 +1,9 @@
{% extends "base.ahk" %}
{% block body %}
WinWait,{{title}},{{text}},{{timeout}},{{exclude_title}},{{exclude_text}}
if !ErrorLevel
{
WinGet, output, ID
FileAppend,%output%,*
}
{% endblock body %}
51 changes: 42 additions & 9 deletions ahk/window.py
Expand Up @@ -513,14 +513,6 @@ def show(self):
"""
return self._base_method('WinShow') or None

def wait(self, seconds_to_wait=''):
"""
:param seconds_to_wait:
:return:
"""
return self._base_method('WinWait', seconds_to_wait=seconds_to_wait, blocking=True) or None

def wait_active(self, seconds_to_wait=''):
"""
Expand Down Expand Up @@ -652,6 +644,30 @@ def win_get(self, title='', text='', exclude_title='', exclude_text='', encoding
script = self._win_get(title=title, text=text, exclude_title=exclude_title, exclude_text=exclude_text)
encoding = encoding or self.window_encoding
ahk_id = self.run_script(script)
if not ahk_id:
return None
return Window(engine=self, ahk_id=ahk_id, encoding=encoding)

def win_wait(self, *, title='', text='', exclude_title='', timeout=0.5, exclude_text='', encoding=None):
"""
WinWait
Wait for a window. If found within the timeout (in seconds), returns a Window object.
If not found, raises a TimeoutError
ref: https://www.autohotkey.com/docs/commands/WinWait.htm
"""
script = self.render_template(
'window/win_wait.ahk',
title=title,
text=text,
exclude_title=exclude_title,
timeout=timeout,
exclude_text=exclude_text,
)
encoding = encoding or self.window_encoding
ahk_id = self.run_script(script)
if not ahk_id:
raise TimeoutError(f'No window found after timeout ({timeout})')
return Window(engine=self, ahk_id=ahk_id, encoding=encoding)

def _win_set(self, subcommand, *args, blocking=True):
Expand Down Expand Up @@ -948,6 +964,8 @@ async def win_get(self, *args, **kwargs):
encoding = kwargs.pop('encoding', self.window_encoding)
script = self._win_get(*args, **kwargs)
ahk_id = await self.a_run_script(script)
if not ahk_id:
return None
return AsyncWindow(engine=self, ahk_id=ahk_id, encoding=encoding)

async def _all_window_ids(self):
Expand Down Expand Up @@ -1004,7 +1022,7 @@ async def find_window(self, func=None, **kwargs):
"""
async for window in self.find_windows(func=func, **kwargs):
return window # return the first result
raise WindowNotFoundError('yikes')
return None

async def find_windows_by_title(self, title, exact=False):
"""
Expand Down Expand Up @@ -1067,3 +1085,18 @@ async def find_window_by_class(self, *args, **kwargs):
"""
async for window in self.find_windows_by_class(*args, **kwargs):
return window

async def win_wait(self, *, title='', text='', exclude_title='', timeout=0.5, exclude_text='', encoding=None):
script = self.render_template(
'window/win_wait.ahk',
title=title,
text=text,
exclude_title=exclude_title,
timeout=timeout,
exclude_text=exclude_text,
)
encoding = encoding or self.window_encoding
ahk_id = await self.a_run_script(script)
if not ahk_id:
raise TimeoutError(f'No window found after timeout ({timeout})')
return AsyncWindow(engine=self, ahk_id=ahk_id, encoding=encoding)
7 changes: 7 additions & 0 deletions docs/README.md
Expand Up @@ -94,6 +94,13 @@ win = list(ahk.windows()) # list of all windows
win = Window(ahk, ahk_id='0xabc123') # by ahk_id
win = Window.from_mouse_position(ahk) # the window under the mouse cursor
win = Window.from_pid(ahk, pid='20366') # by process ID

# Wait for a window
try:
# wait up to 5 seconds for notepad
win = ahk.win_wait(title='Untitled - Notepad', timeout=5)
except TimeoutError:
print('Notepad was not found!')
```

### Working with windows
Expand Down
9 changes: 2 additions & 7 deletions tests/unittests/test_daemon_async.py
Expand Up @@ -177,13 +177,8 @@ async def test_get_calculator(self):

async def test_win_close(self):
await self.win.close()
try:
win = await self.ahk.win_get(title='Untitled - Notepad')
await win.position
except WindowNotFoundError as e:
pass
else:
raise AssertionError('Expected WindowNotFoundError')
win = await self.ahk.win_get(title='Untitled - Notepad')
assert win is None

async def test_find_window_func(self):
async def func(win):
Expand Down
3 changes: 1 addition & 2 deletions tests/unittests/test_win_get.py
Expand Up @@ -34,8 +34,7 @@ def test_win_close():
assert win
assert win.position
win.close()
with pytest.raises(WindowNotFoundError):
ahk.win_get(title='Untitled - Notepad').position
assert ahk.win_get(title='Untitled - Notepad') is None
finally:
if p is not None:
p.terminate()
Expand Down
5 changes: 3 additions & 2 deletions tests/unittests/test_win_get_async.py
Expand Up @@ -29,11 +29,12 @@ async def test_get_calculator(self):

async def a_win_get(self):
win = await self.ahk.win_get(title='Untitled - Notepad')
await win.position
return win

def test_win_close(self):
asyncio.run(self.win.close())
self.assertRaises(WindowNotFoundError, asyncio.run, self.a_win_get())
win = asyncio.run(self.a_win_get())
assert win is None

async def test_find_window_func(self):
async def func(win):
Expand Down
23 changes: 23 additions & 0 deletions tests/unittests/test_window.py
Expand Up @@ -3,11 +3,14 @@
from unittest import TestCase
import os, sys

import pytest

project_root = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../..'))
sys.path.insert(0, project_root)

from ahk import AHK
from ahk.daemon import AHKDaemon
from ahk.window import WindowNotFoundError


class TestWindow(TestCase):
Expand Down Expand Up @@ -99,6 +102,26 @@ def test_title_change(self):
def tearDown(self):
self.p.terminate()

def test_find_window(self):
win = self.ahk.find_window(title=b'Untitled - Notepad')
assert win.id == self.win.id

def test_find_window_nonexistent_is_none(self):
win = self.ahk.find_window(title=b'This should not exist')
assert win is None

def test_winget_nonexistent_window_is_none(self):
win = self.ahk.win_get(title='This should not exist')
assert win is None

def test_winwait_nonexistent_raises_timeout_error(self):
with pytest.raises(TimeoutError):
win = self.ahk.win_wait(title='This should not exist')

def test_winwait_existing_window(self):
win = self.ahk.win_wait(title='Untitled - Notepad')
assert win.id == self.win.id


class TestWindowDaemon(TestWindow):
def setUp(self):
Expand Down
22 changes: 22 additions & 0 deletions tests/unittests/test_window_async.py
Expand Up @@ -5,6 +5,8 @@
import os
import sys

import pytest

project_root = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../..'))
sys.path.insert(0, project_root)
from ahk import AHK, AsyncAHK
Expand Down Expand Up @@ -104,6 +106,26 @@ async def test_title_setter(self):
await self.win.set_title('new title')
assert await self.win.get_title() != starting_title

async def test_find_window(self):
win = await self.ahk.find_window(title=b'Untitled - Notepad')
assert win.id == self.win.id

async def test_find_window_nonexistent_is_none(self):
win = await self.ahk.find_window(title=b'This should not exist')
assert win is None

async def test_winget_nonexistent_window_is_none(self):
win = await self.ahk.win_get(title='This should not exist')
assert win is None

async def test_winwait_nonexistent_raises_timeout_error(self):
with pytest.raises(TimeoutError):
win = await self.ahk.win_wait(title='This should not exist')

async def test_winwait_existing_window(self):
win = await self.ahk.win_wait(title='Untitled - Notepad')
assert win.id == self.win.id

def tearDown(self):
self.p.terminate()
asyncio.run(asyncio.sleep(0.5))

0 comments on commit af37364

Please sign in to comment.