Skip to content

Commit e081767

Browse files
committed
Add window z-order control (topmost / front / back)
1 parent 1ceceff commit e081767

15 files changed

Lines changed: 335 additions & 1 deletion

File tree

README/WHATS_NEW_zh-CN.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 本次更新 — AutoControl
22

3+
## 本次更新 (2026-06-23) — 窗口 Z-order(置顶 / 最前 / 最后)
4+
5+
把窗口钉在最上层、移到最前、或推到后面。完整参考:[`docs/source/Zh/doc/new_features/v147_features_doc.rst`](../docs/source/Zh/doc/new_features/v147_features_doc.rst)
6+
7+
- **`set_topmost` / `bring_to_front` / `send_to_back` / `plan_zorder`**(`AC_set_topmost``AC_bring_to_front``AC_send_to_back`):原始 `set_window_position` 存在但未在 facade、无标题包装也无 topmost 语意——缺少标准 RPA 的「置顶」。`plan_zorder` 是纯动作→`SetWindowPos` 常数查找(可无头测试);以标题操作的设定器透过可注入 driver(`snap_window` 接缝模式)套用,默认为 Win32。
8+
39
## 本次更新 (2026-06-23) — 局部动态 / 活动检测
410

511
找出两帧之间哪些子区域在动。完整参考:[`docs/source/Zh/doc/new_features/v146_features_doc.rst`](../docs/source/Zh/doc/new_features/v146_features_doc.rst)

README/WHATS_NEW_zh-TW.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 本次更新 — AutoControl
22

3+
## 本次更新 (2026-06-23) — 視窗 Z-order(置頂 / 最前 / 最後)
4+
5+
把視窗釘在最上層、移到最前、或推到後面。完整參考:[`docs/source/Zh/doc/new_features/v147_features_doc.rst`](../docs/source/Zh/doc/new_features/v147_features_doc.rst)
6+
7+
- **`set_topmost` / `bring_to_front` / `send_to_back` / `plan_zorder`**(`AC_set_topmost``AC_bring_to_front``AC_send_to_back`):原始 `set_window_position` 存在但未在 facade、無標題包裝也無 topmost 語意——缺少標準 RPA 的「置頂」。`plan_zorder` 是純動作→`SetWindowPos` 常數查找(可無頭測試);以標題操作的設定器透過可注入 driver(`snap_window` 接縫模式)套用,預設為 Win32。
8+
39
## 本次更新 (2026-06-23) — 局部動態 / 活動偵測
410

511
找出兩幀之間哪些子區域在動。完整參考:[`docs/source/Zh/doc/new_features/v146_features_doc.rst`](../docs/source/Zh/doc/new_features/v146_features_doc.rst)

WHATS_NEW.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# What's New — AutoControl
22

3+
## What's new (2026-06-23) — Window Z-Order (Always-On-Top / Front / Back)
4+
5+
Pin a window on top, raise it, or push it behind. Full reference: [`docs/source/Eng/doc/new_features/v147_features_doc.rst`](docs/source/Eng/doc/new_features/v147_features_doc.rst).
6+
7+
- **`set_topmost` / `bring_to_front` / `send_to_back` / `plan_zorder`** (`AC_set_topmost`, `AC_bring_to_front`, `AC_send_to_back`): the raw `set_window_position` existed but wasn't in the facade, had no title wrapper and no topmost semantics — the standard RPA "always-on-top" was missing. `plan_zorder` is a pure action→`SetWindowPos` constant lookup (headless-testable); the title-based setters apply it through an injectable driver (the `snap_window` seam pattern), Win32 by default.
8+
39
## What's new (2026-06-23) — Localized Motion / Activity Detection
410

511
Find which sub-regions are animating between two frames. Full reference: [`docs/source/Eng/doc/new_features/v146_features_doc.rst`](docs/source/Eng/doc/new_features/v146_features_doc.rst).
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Window Z-Order — Always-On-Top / Front / Back
2+
=============================================
3+
4+
``windows_window_manage.set_window_position`` exists at the raw Win32 layer but is not
5+
exported in the package facade, has no title-based wrapper, and no topmost / not-topmost
6+
semantics — and there was no ``always_on_top`` anywhere outside GUI overlay code. This
7+
adds the standard RPA z-order primitive: a pure ``plan_zorder`` that maps an action to
8+
the ``SetWindowPos`` insert-after constant, plus title-based ``set_topmost`` /
9+
``bring_to_front`` / ``send_to_back`` over an injectable driver (the same seam pattern
10+
as ``snap_window``).
11+
12+
The planning is pure and headless-testable; only the default driver touches Win32
13+
(returning ``False`` on other platforms). Imports no ``PySide6``.
14+
15+
Headless API
16+
------------
17+
18+
.. code-block:: python
19+
20+
from je_auto_control import (set_topmost, bring_to_front, send_to_back,
21+
plan_zorder)
22+
23+
set_topmost("Media Player") # pin always-on-top
24+
set_topmost("Media Player", False) # release
25+
bring_to_front("Editor")
26+
send_to_back("Background Monitor")
27+
28+
plan_zorder("topmost")["insert_after"] # -1 (HWND_TOPMOST), pure / testable
29+
30+
``plan_zorder(action)`` (``top`` / ``bottom`` / ``topmost`` / ``notopmost``) returns the
31+
``SetWindowPos`` descriptor (``insert_after`` constant + ``SWP_NOMOVE`` / ``SWP_NOSIZE``
32+
flags); unknown actions raise ``ValueError``. ``set_topmost`` / ``bring_to_front`` /
33+
``send_to_back`` resolve the window by title and apply the action through the default
34+
Win32 driver (or an injected one in tests), returning whether it was applied.
35+
36+
Executor commands
37+
-----------------
38+
39+
``AC_set_topmost`` (``title`` / ``on`` → ``{applied}``), ``AC_bring_to_front`` and
40+
``AC_send_to_back`` (``title`` → ``{applied}``). They are exposed as the MCP tools
41+
``ac_set_topmost`` / ``ac_bring_to_front`` / ``ac_send_to_back`` and as Script Builder
42+
commands under **Window**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ Comprehensive guides for all AutoControl features.
169169
doc/new_features/v144_features_doc
170170
doc/new_features/v145_features_doc
171171
doc/new_features/v146_features_doc
172+
doc/new_features/v147_features_doc
172173
doc/ocr_backends/ocr_backends_doc
173174
doc/observability/observability_doc
174175
doc/operations_layer/operations_layer_doc
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
視窗 Z-order——置頂 / 移到最前 / 移到最後
2+
=========================================
3+
4+
``windows_window_manage.set_window_position`` 在原始 Win32 層存在,但未在套件 facade 匯出、沒有以標題為基礎的包裝、
5+
也沒有 topmost / not-topmost 語意——而 GUI 疊圖以外的地方完全沒有 ``always_on_top``。本功能加入標準 RPA z-order
6+
基本能力:純函式 ``plan_zorder`` 將動作對應到 ``SetWindowPos`` 的 insert-after 常數,以及以標題操作、可注入 driver
7+
的 ``set_topmost`` / ``bring_to_front`` / ``send_to_back``(與 ``snap_window`` 相同的接縫模式)。
8+
9+
規劃為純函式且可無頭測試;只有預設 driver 觸及 Win32(其他平台回傳 ``False``)。不匯入 ``PySide6``。
10+
11+
無頭 API
12+
--------
13+
14+
.. code-block:: python
15+
16+
from je_auto_control import (set_topmost, bring_to_front, send_to_back,
17+
plan_zorder)
18+
19+
set_topmost("Media Player") # 置頂
20+
set_topmost("Media Player", False) # 取消置頂
21+
bring_to_front("Editor")
22+
send_to_back("Background Monitor")
23+
24+
plan_zorder("topmost")["insert_after"] # -1(HWND_TOPMOST),純 / 可測
25+
26+
``plan_zorder(action)``(``top`` / ``bottom`` / ``topmost`` / ``notopmost``)回傳 ``SetWindowPos`` 描述符
27+
(``insert_after`` 常數 + ``SWP_NOMOVE`` / ``SWP_NOSIZE`` 旗標);未知動作丟出 ``ValueError``。``set_topmost`` /
28+
``bring_to_front`` / ``send_to_back`` 以標題解析視窗並透過預設 Win32 driver(測試時注入)套用動作,回傳是否已套用。
29+
30+
執行器命令
31+
----------
32+
33+
``AC_set_topmost``(``title`` / ``on`` → ``{applied}``)、``AC_bring_to_front`` 與 ``AC_send_to_back``
34+
(``title`` → ``{applied}``)。它們以 MCP 工具 ``ac_set_topmost`` / ``ac_bring_to_front`` / ``ac_send_to_back``
35+
以及 Script Builder 中 **Window** 分類下的命令提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ AutoControl 所有功能的完整使用指南。
169169
doc/new_features/v144_features_doc
170170
doc/new_features/v145_features_doc
171171
doc/new_features/v146_features_doc
172+
doc/new_features/v147_features_doc
172173
doc/ocr_backends/ocr_backends_doc
173174
doc/observability/observability_doc
174175
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,10 @@
347347
from je_auto_control.utils.motion_regions import (
348348
activity_score, changed_regions, has_motion,
349349
)
350+
# Window z-order control (topmost / bring-to-front / send-to-back)
351+
from je_auto_control.utils.window_zorder import (
352+
bring_to_front, plan_zorder, send_to_back, set_topmost,
353+
)
350354
# CI workflow annotations (GitHub Actions)
351355
from je_auto_control.utils.ci_annotations import (
352356
emit_annotations, format_annotation,
@@ -1209,6 +1213,10 @@ def start_autocontrol_gui(*args, **kwargs):
12091213
"changed_regions",
12101214
"has_motion",
12111215
"activity_score",
1216+
"plan_zorder",
1217+
"set_topmost",
1218+
"bring_to_front",
1219+
"send_to_back",
12121220
"emit_annotations", "format_annotation",
12131221
"ClipboardHistory", "default_clipboard_history",
12141222
"analyze_heal_log", "heal_stats", "scan_secrets",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,24 @@ def _add_window_specs(specs: List[CommandSpec]) -> None:
676676
),
677677
description="Cascade a list of windows diagonally.",
678678
))
679+
specs.append(CommandSpec(
680+
"AC_set_topmost", "Window", "Set Always-On-Top",
681+
fields=(
682+
FieldSpec("title", FieldType.STRING),
683+
FieldSpec("on", FieldType.BOOL, optional=True, default=True),
684+
),
685+
description="Pin a window always-on-top (or release it).",
686+
))
687+
specs.append(CommandSpec(
688+
"AC_bring_to_front", "Window", "Bring Window to Front",
689+
fields=(FieldSpec("title", FieldType.STRING),),
690+
description="Raise a window to the top of the z-order.",
691+
))
692+
specs.append(CommandSpec(
693+
"AC_send_to_back", "Window", "Send Window to Back",
694+
fields=(FieldSpec("title", FieldType.STRING),),
695+
description="Send a window to the bottom of the z-order.",
696+
))
679697
specs.append(CommandSpec(
680698
"AC_wait_window_closed", "Window", "Wait for Window to Close",
681699
fields=(

je_auto_control/utils/executor/action_executor.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3735,6 +3735,24 @@ def _resolve_after(after: Any):
37353735
return np.asarray(pil_screenshot().convert("RGB"))
37363736

37373737

3738+
def _set_topmost(title: str, on: Any = True) -> Dict[str, Any]:
3739+
"""Adapter: pin a window always-on-top (or release it)."""
3740+
from je_auto_control.utils.window_zorder import set_topmost
3741+
return {"applied": set_topmost(title, bool(on))}
3742+
3743+
3744+
def _bring_to_front(title: str) -> Dict[str, Any]:
3745+
"""Adapter: raise a window to the top of the z-order."""
3746+
from je_auto_control.utils.window_zorder import bring_to_front
3747+
return {"applied": bring_to_front(title)}
3748+
3749+
3750+
def _send_to_back(title: str) -> Dict[str, Any]:
3751+
"""Adapter: send a window to the bottom of the z-order."""
3752+
from je_auto_control.utils.window_zorder import send_to_back
3753+
return {"applied": send_to_back(title)}
3754+
3755+
37383756
def _with_modifiers(modifiers: Any, actions: Any) -> Dict[str, Any]:
37393757
"""Adapter: run nested actions while modifier keys are held down."""
37403758
import json
@@ -5482,6 +5500,9 @@ def __init__(self):
54825500
"AC_histogram_changed": _histogram_changed,
54835501
"AC_changed_regions": _changed_regions,
54845502
"AC_has_motion": _has_motion,
5503+
"AC_set_topmost": _set_topmost,
5504+
"AC_bring_to_front": _bring_to_front,
5505+
"AC_send_to_back": _send_to_back,
54855506
"AC_tile_rect": _tile_rect,
54865507
"AC_grid_rects": _grid_rects,
54875508
"AC_cascade_rects": _cascade_rects,

0 commit comments

Comments
 (0)