Skip to content

Commit b449ca3

Browse files
committed
Add timed input replay and declarative input-sequence DSL
1 parent 4e404b1 commit b449ca3

15 files changed

Lines changed: 389 additions & 0 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-19) — Timed Input Macros](#whats-new-2026-06-19--timed-input-macros)
1617
- [What's new (2026-06-19) — Semantic Screen State](#whats-new-2026-06-19--semantic-screen-state)
1718
- [What's new (2026-06-19) — Set-of-Marks Overlay](#whats-new-2026-06-19--set-of-marks-overlay)
1819
- [What's new (2026-06-19) — Checkpoint & Resume](#whats-new-2026-06-19--checkpoint--resume)
@@ -76,6 +77,13 @@
7677

7778
---
7879

80+
## What's new (2026-06-19) — Timed Input Macros
81+
82+
Replay input with timing fidelity + a press-hold-release DSL, full stack. Full reference: [`docs/source/Eng/doc/new_features/v24_features_doc.rst`](docs/source/Eng/doc/new_features/v24_features_doc.rst).
83+
84+
- **Timed timeline replay**`replay_timeline(events, speed=...)` (`AC_replay_timeline`, `ac_replay_timeline`): replay events honoring each `delta_ms` gap, scaled by `speed` and clampable; ops = move/click/scroll/press/release/key.
85+
- **Input-sequence DSL**`run_sequence(steps)` (`AC_input_sequence`, `ac_input_sequence`): declarative press/hold/release chords + `repeat`/`wait`. Both inject sink+sleep for deterministic tests.
86+
7987
## What's new (2026-06-19) — Semantic Screen State
8088

8189
The semantic companion to the pixel diff, full stack. Full reference: [`docs/source/Eng/doc/new_features/v23_features_doc.rst`](docs/source/Eng/doc/new_features/v23_features_doc.rst).

README/README_zh-CN.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-19) — 计时输入宏](#本次更新-2026-06-19--计时输入宏)
1516
- [本次更新 (2026-06-19) — 语义屏幕状态](#本次更新-2026-06-19--语义屏幕状态)
1617
- [本次更新 (2026-06-19) — Set-of-Marks 叠图](#本次更新-2026-06-19--set-of-marks-叠图)
1718
- [本次更新 (2026-06-19) — 检查点与续跑](#本次更新-2026-06-19--检查点与续跑)
@@ -75,6 +76,13 @@
7576

7677
---
7778

79+
## 本次更新 (2026-06-19) — 计时输入宏
80+
81+
以时间保真度重播输入 + 按住-放开 DSL,走完整五层。完整参考:[`docs/source/Zh/doc/new_features/v24_features_doc.rst`](../docs/source/Zh/doc/new_features/v24_features_doc.rst)
82+
83+
- **计时时间轴重播**`replay_timeline(events, speed=...)`(`AC_replay_timeline``ac_replay_timeline`):遵守每个 `delta_ms` 间隔、按 `speed` 缩放且可夹限;op = move/click/scroll/press/release/key。
84+
- **输入序列 DSL**`run_sequence(steps)`(`AC_input_sequence``ac_input_sequence`):声明式按住-放开组合键 + `repeat`/`wait`。两者均可注入 sink+sleep 做确定性测试。
85+
7886
## 本次更新 (2026-06-19) — 语义屏幕状态
7987

8088
像素差异的语义对应物,走完整五层。完整参考:[`docs/source/Zh/doc/new_features/v23_features_doc.rst`](../docs/source/Zh/doc/new_features/v23_features_doc.rst)

README/README_zh-TW.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-19) — 計時輸入巨集](#本次更新-2026-06-19--計時輸入巨集)
1516
- [本次更新 (2026-06-19) — 語意螢幕狀態](#本次更新-2026-06-19--語意螢幕狀態)
1617
- [本次更新 (2026-06-19) — Set-of-Marks 疊圖](#本次更新-2026-06-19--set-of-marks-疊圖)
1718
- [本次更新 (2026-06-19) — 檢查點與續跑](#本次更新-2026-06-19--檢查點與續跑)
@@ -75,6 +76,13 @@
7576

7677
---
7778

79+
## 本次更新 (2026-06-19) — 計時輸入巨集
80+
81+
以時間保真度重播輸入 + 按住-放開 DSL,走完整五層。完整參考:[`docs/source/Zh/doc/new_features/v24_features_doc.rst`](../docs/source/Zh/doc/new_features/v24_features_doc.rst)
82+
83+
- **計時時間軸重播**`replay_timeline(events, speed=...)`(`AC_replay_timeline``ac_replay_timeline`):遵守每個 `delta_ms` 間隔、依 `speed` 縮放且可夾限;op = move/click/scroll/press/release/key。
84+
- **輸入序列 DSL**`run_sequence(steps)`(`AC_input_sequence``ac_input_sequence`):宣告式按住-放開組合鍵 + `repeat`/`wait`。兩者皆可注入 sink+sleep 做決定性測試。
85+
7886
## 本次更新 (2026-06-19) — 語意螢幕狀態
7987

8088
像素差異的語意對應物,走完整五層。完整參考:[`docs/source/Zh/doc/new_features/v23_features_doc.rst`](../docs/source/Zh/doc/new_features/v23_features_doc.rst)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
==================================================
2+
New Features (2026-06-19) — Timed Input Macros
3+
==================================================
4+
5+
Replay recorded input with timing fidelity, and author press-hold-release
6+
combos with a small declarative DSL. Pure standard library; full stack.
7+
Both dispatch through an injectable sink and sleep, so they unit-test
8+
deterministically with a fake clock and a recording sink.
9+
10+
.. contents::
11+
:local:
12+
:depth: 2
13+
14+
15+
Timed timeline replay
16+
====================
17+
18+
::
19+
20+
from je_auto_control import replay_timeline
21+
22+
events = [{"op": "move", "x": 10, "y": 10, "delta_ms": 0},
23+
{"op": "click", "x": 10, "y": 10, "delta_ms": 120},
24+
{"op": "key", "key": "a", "delta_ms": 80}]
25+
replay_timeline(events, speed=2.0) # plays twice as fast; gaps clampable
26+
27+
Each event's ``delta_ms`` gap is honored, divided by ``speed`` (and clamped
28+
to ``[min_gap, max_gap]``). Event ``op`` is one of ``move`` / ``click`` /
29+
``scroll`` / ``press`` / ``release`` / ``key``. Exposed as
30+
``AC_replay_timeline`` / ``ac_replay_timeline``.
31+
32+
33+
Input-sequence DSL
34+
=================
35+
36+
::
37+
38+
from je_auto_control import run_sequence
39+
40+
run_sequence([
41+
{"op": "press", "key": "ctrl"},
42+
{"op": "repeat", "times": 3, "steps": [{"op": "key", "key": "a"}]},
43+
{"op": "wait", "ms": 50},
44+
{"op": "release", "key": "ctrl"},
45+
])
46+
47+
A declarative mini-language for press-hold-release chords and repeated
48+
input: action ops (``press`` / ``release`` / ``key`` / ``click`` / ``move``
49+
/ ``scroll``) plus control ops ``{op: wait, ms}`` and
50+
``{op: repeat, times, steps:[...]}``. Returns the flattened executed log.
51+
Exposed as ``AC_input_sequence`` / ``ac_input_sequence``.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Comprehensive guides for all AutoControl features.
4646
doc/new_features/v21_features_doc
4747
doc/new_features/v22_features_doc
4848
doc/new_features/v23_features_doc
49+
doc/new_features/v24_features_doc
4950
doc/ocr_backends/ocr_backends_doc
5051
doc/observability/observability_doc
5152
doc/operations_layer/operations_layer_doc
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
==========================================
2+
新功能 (2026-06-19) — 計時輸入巨集
3+
==========================================
4+
5+
以時間保真度重播錄製的輸入,並用一個小型宣告式 DSL 編寫按住-放開的
6+
組合鍵。純標準庫;走完整五層。兩者都透過可注入的 sink 與 sleep 派發,
7+
因此能用假時鐘與記錄式 sink 做決定性單元測試。
8+
9+
.. contents::
10+
:local:
11+
:depth: 2
12+
13+
14+
計時時間軸重播
15+
==============
16+
17+
::
18+
19+
from je_auto_control import replay_timeline
20+
21+
events = [{"op": "move", "x": 10, "y": 10, "delta_ms": 0},
22+
{"op": "click", "x": 10, "y": 10, "delta_ms": 120},
23+
{"op": "key", "key": "a", "delta_ms": 80}]
24+
replay_timeline(events, speed=2.0) # 兩倍速播放;間隔可夾限
25+
26+
每個事件的 ``delta_ms`` 間隔都會被遵守,並除以 ``speed``(且夾限在
27+
``[min_gap, max_gap]``)。事件 ``op`` 為 ``move`` / ``click`` / ``scroll`` /
28+
``press`` / ``release`` / ``key`` 之一。對應 ``AC_replay_timeline`` /
29+
``ac_replay_timeline``。
30+
31+
32+
輸入序列 DSL
33+
============
34+
35+
::
36+
37+
from je_auto_control import run_sequence
38+
39+
run_sequence([
40+
{"op": "press", "key": "ctrl"},
41+
{"op": "repeat", "times": 3, "steps": [{"op": "key", "key": "a"}]},
42+
{"op": "wait", "ms": 50},
43+
{"op": "release", "key": "ctrl"},
44+
])
45+
46+
用於按住-放開組合鍵與重複輸入的宣告式迷你語言:動作 op(``press`` /
47+
``release`` / ``key`` / ``click`` / ``move`` / ``scroll``)加上控制 op
48+
``{op: wait, ms}`` 與 ``{op: repeat, times, steps:[...]}``。回傳攤平後的
49+
執行記錄。對應 ``AC_input_sequence`` / ``ac_input_sequence``。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ AutoControl 所有功能的完整使用指南。
4646
doc/new_features/v21_features_doc
4747
doc/new_features/v22_features_doc
4848
doc/new_features/v23_features_doc
49+
doc/new_features/v24_features_doc
4950
doc/ocr_backends/ocr_backends_doc
5051
doc/observability/observability_doc
5152
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@
174174
describe_screen, diff_snapshots, screen_changed, snapshot,
175175
snapshot_screen,
176176
)
177+
# Timed input replay + declarative input-sequence DSL
178+
from je_auto_control.utils.input_macro import replay_timeline, run_sequence
177179
# Background popup/interrupt watchdog (unattended automation)
178180
from je_auto_control.utils.watchdog import (
179181
PopupWatchdog, WatchdogRule, default_popup_watchdog,
@@ -601,6 +603,7 @@ def start_autocontrol_gui(*args, **kwargs):
601603
"resolve_mark",
602604
"describe_screen", "diff_snapshots", "screen_changed", "snapshot",
603605
"snapshot_screen",
606+
"replay_timeline", "run_sequence",
604607
# MCP server
605608
"AuditLogger", "HttpMCPServer", "MCPContent", "MCPPrompt",
606609
"MCPPromptArgument", "MCPResource", "MCPServer", "MCPTool",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,21 @@ def _add_misc_specs(specs: List[CommandSpec]) -> None:
663663
_add_checkpoint_specs(specs)
664664
_add_set_of_marks_specs(specs)
665665
_add_screen_state_specs(specs)
666+
_add_input_macro_specs(specs)
667+
668+
669+
def _add_input_macro_specs(specs: List[CommandSpec]) -> None:
670+
specs.append(CommandSpec(
671+
"AC_replay_timeline", "Flow", "Replay Timed Events",
672+
fields=(FieldSpec("speed", FieldType.FLOAT, optional=True,
673+
default=1.0),),
674+
description="Replay 'events' (JSON view) honoring delta_ms, scaled by "
675+
"speed.",
676+
))
677+
specs.append(CommandSpec(
678+
"AC_input_sequence", "Flow", "Run Input Sequence (DSL)",
679+
description="Run 'steps' (JSON view): press/hold/release/repeat/wait.",
680+
))
666681

667682

668683
def _add_screen_state_specs(specs: List[CommandSpec]) -> None:

je_auto_control/utils/executor/action_executor.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,6 +2781,19 @@ def _describe_screen(app_name: Optional[str] = None) -> Dict[str, Any]:
27812781
return describe_screen(app_name=app_name)
27822782

27832783

2784+
def _replay_timeline(events: List[Dict[str, Any]],
2785+
speed: float = 1.0) -> Dict[str, Any]:
2786+
"""Adapter: replay timed input events at a speed multiplier."""
2787+
from je_auto_control.utils.input_macro import replay_timeline
2788+
return {"played": replay_timeline(events, speed=float(speed))}
2789+
2790+
2791+
def _input_sequence(steps: List[Dict[str, Any]]) -> Dict[str, Any]:
2792+
"""Adapter: run a declarative input sequence (press/hold/repeat/...)."""
2793+
from je_auto_control.utils.input_macro import run_sequence
2794+
return {"log": run_sequence(steps)}
2795+
2796+
27842797
class Executor:
27852798
"""
27862799
Executor
@@ -2997,6 +3010,8 @@ def __init__(self):
29973010
"AC_screen_diff": _screen_diff,
29983011
"AC_screen_changed": _screen_changed,
29993012
"AC_describe_screen": _describe_screen,
3013+
"AC_replay_timeline": _replay_timeline,
3014+
"AC_input_sequence": _input_sequence,
30003015
"AC_a11y_record_start": _a11y_record_start,
30013016
"AC_a11y_record_stop": _a11y_record_stop,
30023017
"AC_a11y_record_events": _a11y_record_events,

0 commit comments

Comments
 (0)