Skip to content

Commit 93d640c

Browse files
committed
Revert "Experiment: Interruptible AHK commands"
This reverts commit cf429f0.
1 parent cf429f0 commit 93d640c

File tree

5 files changed

+48
-57
lines changed

5 files changed

+48
-57
lines changed

ahkpy/Python.ahk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,14 @@ Main() {
109109
handleCtrlEventCB := RegisterCallback("HandleCtrlEvent", "Fast")
110110
DllCall("SetConsoleCtrlHandler", "Ptr", handleCtrlEventCB, "Int", true)
111111

112-
SetTimer, CheckSignals, 100
113-
114112
result := PyObject_CallObject(mainFunc, NULL)
115113
Py_DecRef(mainFunc)
116114
if (result == NULL) {
117115
PrintErrorOrExit()
118116
}
119117
Py_DecRef(result)
118+
119+
SetTimer, CheckSignals, 100
120120
}
121121

122122
PackBuiltinModule() {

ahkpy/clipboard.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import functools
33
from typing import Callable
44

5-
from .flow import ahk_call, _wrap_callback
5+
from .flow import ahk_call, _wait_for, _wrap_callback
66

77
__all__ = [
88
"ClipboardHandler",
@@ -36,18 +36,13 @@ def wait_clipboard(timeout: float = None) -> str:
3636
3737
If there is no text in the clipboard after *timeout* seconds, then an empty
3838
string will be returned. If *timeout* is not specified or ``None``, there is
39-
no limit to the wait time. Specifying 0 is the same as specifying 0.5.
39+
no limit to the wait time.
4040
4141
:command: `ClipWait
4242
<https://www.autohotkey.com/docs/commands/ClipWait.htm>`_
4343
"""
4444
# TODO: Implement WaitForAnyData argument.
45-
if timeout is not None:
46-
timeout = float(timeout)
47-
ok = ahk_call("ClipWait", timeout)
48-
if not ok:
49-
return ""
50-
return get_clipboard()
45+
return _wait_for(timeout, get_clipboard) or ""
5146

5247

5348
def on_clipboard_change(func: Callable = None, *args, prepend_handler=False):

ahkpy/flow.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import queue
55
import sys
66
import threading
7+
import time
78

89
import _ahk
910

@@ -54,12 +55,31 @@ def sleep(secs):
5455
"""
5556
if not isinstance(secs, (int, float)):
5657
raise TypeError(f"a number is required (got type {secs.__class__.__name__})")
58+
_wait_for(secs, None)
59+
60+
61+
def _wait_for(secs, check_fn):
62+
if secs is None:
63+
secs = float("inf")
64+
5765
if secs < 0:
5866
raise ValueError("sleep length must be non-negative")
59-
elif secs == 0:
60-
ahk_call("Sleep", 0)
67+
elif secs <= _poll_interval:
68+
time.sleep(secs)
69+
poll()
70+
return check_fn and check_fn()
6171
else:
62-
ahk_call("Sleep", int(secs * 1000))
72+
stop = time.perf_counter() + secs
73+
while time.perf_counter() < stop:
74+
time.sleep(_poll_interval)
75+
poll()
76+
result = check_fn and check_fn()
77+
if result:
78+
return result
79+
80+
81+
# The interval between AHK message queue polls during the blocking operations.
82+
_poll_interval = 0.01
6383

6484

6585
def poll():
@@ -130,10 +150,6 @@ def output_debug(*objects, sep=" "):
130150
ctypes.windll.kernel32.OutputDebugStringW(debug_str)
131151

132152

133-
# The interval between AHK message queue polls during the blocking operations.
134-
_poll_interval = 0.01
135-
136-
137153
def coop(func, *args, **kwargs):
138154
"""Run the given function in a new thread and make it cooperate with AHK's
139155
event loop.

ahkpy/key_state.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from .flow import ahk_call
1+
import functools
2+
3+
from .flow import ahk_call, _wait_for
24

35
__all__ = [
46
"get_caps_lock_state",
@@ -96,34 +98,22 @@ def wait_key_pressed(key_name, timeout: float = None) -> bool:
9698
after *timeout* seconds, then ``False`` will be returned. If *timeout* is
9799
not specified or ``None``, there is no limit to the wait time.
98100
"""
99-
return _key_wait(key_name, down=True, logical=False, timeout=timeout)
101+
return _wait_for(timeout, functools.partial(is_key_pressed, key_name)) or False
100102

101103

102104
def wait_key_released(key_name, timeout: float = None) -> bool:
103105
"""Wait for a key or mouse/joystick button to be released physically."""
104-
return _key_wait(key_name, down=False, logical=False, timeout=timeout)
106+
return _wait_for(timeout, lambda: not is_key_pressed(key_name)) or False
105107

106108

107109
def wait_key_pressed_logical(key_name, timeout: float = None) -> bool:
108110
"""Wait for a key or mouse/joystick button logical state to be pressed."""
109-
return _key_wait(key_name, down=True, logical=True, timeout=timeout)
111+
return _wait_for(timeout, functools.partial(is_key_pressed_logical, key_name)) or False
110112

111113

112114
def wait_key_released_logical(key_name, timeout: float = None) -> bool:
113115
"""Wait for a key or mouse/joystick button logical state to be released."""
114-
return _key_wait(key_name, down=False, logical=True, timeout=timeout)
115-
116-
117-
def _key_wait(key_name, down=False, logical=False, timeout=None) -> bool:
118-
options = []
119-
if down:
120-
options.append("D")
121-
if logical:
122-
options.append("L")
123-
if timeout is not None:
124-
options.append(f"T{timeout}")
125-
ok = ahk_call("KeyWait", str(key_name), "".join(options))
126-
return bool(ok)
116+
return _wait_for(timeout, lambda: not is_key_pressed_logical(key_name)) or False
127117

128118

129119
def get_key_name(key_name: str) -> str:

ahkpy/window.py

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from . import colors
1010
from . import sending
1111
from .exceptions import Error
12-
from .flow import ahk_call, global_ahk_lock
12+
from .flow import ahk_call, global_ahk_lock, _wait_for
1313
from .hotkey_context import HotkeyContext
1414
from .settings import get_settings, optional_ms
1515
from .unset import UNSET, UnsetType
@@ -280,7 +280,7 @@ def wait(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe=UNSET,
280280
<https://www.autohotkey.com/docs/commands/WinWait.htm>`_
281281
"""
282282
self = self._filter(title, class_name, id, pid, exe, text, match)
283-
return self._wait("WinWait", timeout)
283+
return _wait_for(timeout, self.exist) or Window(None)
284284

285285
def wait_active(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe=UNSET, text=UNSET, match=None,
286286
timeout=None):
@@ -297,7 +297,7 @@ def wait_active(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe
297297
query = self._query()
298298
if query == ("", "", "", ""):
299299
self = dc.replace(self, title="A")
300-
return self._wait("WinWaitActive", timeout)
300+
return _wait_for(timeout, self.get_active) or Window(None)
301301

302302
def wait_inactive(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe=UNSET, text=UNSET, match=None,
303303
timeout=None) -> bool:
@@ -316,7 +316,7 @@ def wait_inactive(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, e
316316
<https://www.autohotkey.com/docs/commands/WinWaitActive.htm>`_
317317
"""
318318
self = self._filter(title, class_name, id, pid, exe, text, match)
319-
return self._wait_close("WinWaitNotActive", timeout)
319+
return _wait_for(timeout, lambda: not self.get_active()) or False
320320

321321
def wait_close(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe=UNSET, text=UNSET, match=None,
322322
timeout=None):
@@ -335,22 +335,9 @@ def wait_close(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe=
335335
<https://www.autohotkey.com/docs/commands/WinWaitClose.htm>`_
336336
"""
337337
self = self._filter(title, class_name, id, pid, exe, text, match)
338-
return self._wait_close("WinWaitClose", timeout)
339-
340-
def _wait(self, cmd, timeout):
341-
win_id = self._call(cmd, *self._include(), timeout, *self._exclude(), set_delay=True)
342-
if not win_id:
343-
return Window(None)
344-
return Window(win_id)
345-
346-
def _wait_close(self, cmd, timeout):
347-
# WinWaitClose and WinWaitNotActive don't set the Last Found Window,
348-
# return False if the wait was timed out.
349-
ok = self._call(cmd, *self._include(), timeout, *self._exclude(), set_delay=True)
350-
if ok is None:
351-
# There are no matching windows, and that's what we are waiting for.
352-
return True
353-
return bool(ok)
338+
# WinWaitClose doesn't set Last Found Window, return False if the wait
339+
# was timed out.
340+
return _wait_for(timeout, lambda: not self.exist()) or False
354341

355342
def close_all(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe=UNSET, text=UNSET, match=None,
356343
timeout=None):
@@ -468,9 +455,9 @@ def _group_action(self, cmd, timeout=UNSET):
468455
query_hash_str = str(query_hash).replace("-", "m") # AHK doesn't allow "-" in group names
469456
label = ""
470457
self._call("GroupAdd", query_hash_str, *self._include(), label, *self._exclude())
471-
self._call(cmd, f"ahk_group {query_hash_str}", "", timeout or "", set_delay=True)
458+
self._call(cmd, f"ahk_group {query_hash_str}", "", "", set_delay=True)
472459
if timeout is not UNSET:
473-
return not self.exist()
460+
return self.wait_close(timeout=timeout)
474461

475462
def window_context(self, title=UNSET, *, class_name=UNSET, id=UNSET, pid=UNSET, exe=UNSET, text=UNSET, match=None):
476463
"""window_context(title: str = UNSET, **criteria) -> ahkpy.HotkeyContext
@@ -1974,11 +1961,14 @@ def wait_status_bar(self, bar_text="", *,
19741961
:command: `StatusBarWait
19751962
<https://www.autohotkey.com/docs/commands/StatusBarWait.htm>`_
19761963
"""
1964+
# TODO: StatusBarWait is blocking and is not interruptable. However, it
1965+
# is usually more efficient to use StatusBarWait rather than calling
1966+
# StatusBarGetText in a loop.
19771967
try:
19781968
ok = self._call(
19791969
"StatusBarWait",
19801970
bar_text,
1981-
timeout if timeout is not None else "",
1971+
timeout,
19821972
part + 1,
19831973
*self._include(),
19841974
interval * 1000,

0 commit comments

Comments
 (0)