Skip to content

feat: Add controller inactive action to restore window/input state#1155

Merged
MistEO merged 4 commits intomainfrom
feat/inactive
Feb 27, 2026
Merged

feat: Add controller inactive action to restore window/input state#1155
MistEO merged 4 commits intomainfrom
feat/inactive

Conversation

@MistEO
Copy link
Member

@MistEO MistEO commented Feb 27, 2026

@MaaXYZ/binding-developers 看看,这个接口主要是给 win32 controller 恢复窗口位置、解除 block 用的。暴露了 API 但其实没啥大用,tasker 里面每次执行完已经主动调用了,貌似没什么需要手动调用的场景

@ZeroAd-06 佬也帮忙瞅瞅恢复部分有没有问题

Summary by Sourcery

在自动化任务完成后,新增一个“inactive”(非激活)控制器动作,用于恢复窗口/输入的正常状态,并在核心、平台控制单元以及各语言绑定中对其进行暴露。

New Features:

  • 在核心控制器 API 和控制单元抽象中引入控制器的 inactive 动作,用于将控制器切换到非激活状态。
  • 通过 C、C++ 模块、Python 和 Node.js 绑定暴露该 inactive 动作,包括自定义控制器回调以及远程/代理消息机制。
  • 当所有队列中的任务完成后,由 tasker 自动发送一次 inactive 动作,以恢复运行环境。

Enhancements:

  • 为 Win32 控制器实现平台特定的 inactive 行为,用于恢复伪最小化窗口、移除置顶标志以及解除对用户输入的阻塞,而在其他平台上该操作为空操作(no-op)。
  • 扩展异步运行器(async runner),加入 pending 查询功能,以支持决策何时发送 inactive 动作。

Tests:

  • 扩展 Python 和 Node.js 绑定测试,包括自定义控制器测试,以覆盖新的 inactive 控制器动作。
Original summary in English

Summary by Sourcery

Add an "inactive" controller action to restore normal window/input state after automation tasks and expose it across core, platform control units, and language bindings.

New Features:

  • Introduce a controller inactive action in the core controller API and control unit abstraction to transition controllers to a non-active state.
  • Expose the inactive action through C, C++ module, Python, and Node.js bindings, including custom controller callbacks and remote/agent messaging.
  • Automatically post an inactive action from the tasker when all queued tasks are finished to restore the environment.

Enhancements:

  • Implement platform-specific inactive behavior for Win32 controllers to revert pseudo-minimized windows, remove topmost flags, and unblock user input, while making other platforms no-ops.
  • Extend the async runner with a pending query to support deciding when to send the inactive action.

Tests:

  • Expand Python and Node.js binding tests, including custom controller tests, to cover the new inactive controller action.
Original summary in English

Summary by Sourcery

在自动化任务完成后,新增一个“inactive”(非激活)控制器动作,用于恢复窗口/输入的正常状态,并在核心、平台控制单元以及各语言绑定中对其进行暴露。

New Features:

  • 在核心控制器 API 和控制单元抽象中引入控制器的 inactive 动作,用于将控制器切换到非激活状态。
  • 通过 C、C++ 模块、Python 和 Node.js 绑定暴露该 inactive 动作,包括自定义控制器回调以及远程/代理消息机制。
  • 当所有队列中的任务完成后,由 tasker 自动发送一次 inactive 动作,以恢复运行环境。

Enhancements:

  • 为 Win32 控制器实现平台特定的 inactive 行为,用于恢复伪最小化窗口、移除置顶标志以及解除对用户输入的阻塞,而在其他平台上该操作为空操作(no-op)。
  • 扩展异步运行器(async runner),加入 pending 查询功能,以支持决策何时发送 inactive 动作。

Tests:

  • 扩展 Python 和 Node.js 绑定测试,包括自定义控制器测试,以覆盖新的 inactive 控制器动作。
Original summary in English

Summary by Sourcery

Add an "inactive" controller action to restore normal window/input state after automation tasks and expose it across core, platform control units, and language bindings.

New Features:

  • Introduce a controller inactive action in the core controller API and control unit abstraction to transition controllers to a non-active state.
  • Expose the inactive action through C, C++ module, Python, and Node.js bindings, including custom controller callbacks and remote/agent messaging.
  • Automatically post an inactive action from the tasker when all queued tasks are finished to restore the environment.

Enhancements:

  • Implement platform-specific inactive behavior for Win32 controllers to revert pseudo-minimized windows, remove topmost flags, and unblock user input, while making other platforms no-ops.
  • Extend the async runner with a pending query to support deciding when to send the inactive action.

Tests:

  • Expand Python and Node.js binding tests, including custom controller tests, to cover the new inactive controller action.

Summary by Sourcery

在控制器中新增一个 “inactive” 动作,用于在任务完成后重置控制器/窗口状态,并在核心、平台控制单元、远程/代理消息以及各语言绑定中对其进行暴露。

New Features:

  • 在核心控制器接口和控制单元 API 中引入控制器 inactive 动作,使控制器可以切换到非活动状态。
  • 在 C API、C++ 模块导出、Python 绑定(包括自定义控制器)以及 Node.js 绑定和类型定义中暴露 inactive 控制器动作。
  • 允许 tasker 在所有已排队任务完成后自动发送一个 inactive 动作。

Enhancements:

  • 为 Win32 控制单元实现平台相关的 inactive 处理,用于恢复伪最小化窗口、移除置顶标志并解除用户输入阻塞,而对其他控制单元则基本为空操作(no-op)。
  • 扩展异步运行器(async runner),增加一个 pending 查询,用于在发送 inactive 请求前判断是否仍有剩余动作。

Tests:

  • 更新 Python 和 Node.js 绑定测试,包括自定义控制器测试和代理(agent)测试,以覆盖新的 inactive 控制器动作。
Original summary in English

Summary by Sourcery

Add a controller "inactive" action to reset controller/window state after tasks complete and expose it across core, platform control units, remote/agent messaging, and language bindings.

New Features:

  • Introduce a controller inactive action in the core controller interface and control unit API to transition controllers to a non-active state.
  • Expose the inactive controller action in C API, C++ module exports, Python bindings (including custom controllers), and Node.js bindings and type definitions.
  • Allow tasker to automatically post an inactive action when all queued tasks have finished.

Enhancements:

  • Implement platform-specific inactive handling for Win32 control units to restore pseudo-minimized windows, remove topmost flags, and unblock user input, while making other control units effectively no-ops.
  • Extend the async runner with a pending query to support deciding when there are remaining actions before sending the inactive request.

Tests:

  • Update Python and Node.js binding tests, including custom controller tests and agent tests, to cover the new inactive controller action.

Summary by Sourcery

在控制器中新增一个 “inactive” 操作,用于在任务完成后恢复窗口/输入的正常状态,并通过核心控制器 API、平台控制单元以及各语言绑定对外暴露。

New Features:

  • 在核心控制器接口和控制单元抽象中引入控制器 inactive 操作,用于将控制器切换到非活动状态。
  • 通过 C/C++ API、Python 和 Node.js 绑定对外暴露控制器 inactive 操作,包括对自定义控制器和远程代理消息的支持。
  • 允许 tasker 在所有排队任务完成后自动发送一个 inactive 操作。

Enhancements:

  • 为 Win32 控制器实现平台相关的 inactive 处理,用于恢复伪最小化的窗口状态、移除置顶标志以及解除对用户输入的阻塞,同时让其他平台的实现实际为 no-op。
  • 为异步运行器扩展一个 pending-query 辅助工具,以支持判断何时应发送 inactive 操作。

Tests:

  • 更新 Python 和 Node.js 绑定测试(包括自定义控制器场景和代理测试),以覆盖新的 inactive 控制器操作。
Original summary in English

Summary by Sourcery

Add a controller "inactive" action to restore normal window/input state after tasks complete and expose it across core controller APIs, platform control units, and language bindings.

New Features:

  • Introduce a controller inactive action in the core controller interface and control unit abstraction to transition controllers to a non-active state.
  • Expose the controller inactive action via C/C++ APIs, Python, and Node.js bindings, including support for custom controllers and remote agent messaging.
  • Allow the tasker to automatically post an inactive action when all queued tasks have finished.

Enhancements:

  • Implement platform-specific inactive handling for Win32 controllers to revert pseudo-minimized window state, remove topmost flags, and unblock user input, while making other platforms effectively no-ops.
  • Extend the async runner with a pending-query helper to support determining when to send the inactive action.

Tests:

  • Update Python and Node.js binding tests, including custom controller scenarios and agent tests, to cover the new inactive controller action.

@MistEO MistEO marked this pull request as ready for review February 27, 2026 08:11
Copilot AI review requested due to automatic review settings February 27, 2026 08:11
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些高层反馈:

  • ControllerImpl::post_inactive(NodeJS 绑定)中,EnvType 参数在函数定义里是未命名的,但在函数体中使用了 env,这将无法编译——请为该参数添加一个名称(例如 maajs::EnvType env),以与使用方式保持一致。
  • !task_runner_->pending() 时,Tasker::run_task 中调用 controller_->post_inactive() 的逻辑,可能会与紧接在检查之后入队的新任务产生竞争;建议澄清预期语义,或将“变为 inactive”的状态转换与 runner 状态绑定得更紧密,以避免在仍有任务正在被调度时短暂地将 controller 标记为 inactive。
给 AI Agent 的提示词
请根据以下代码审查评论进行修改:

## Overall Comments
-`ControllerImpl::post_inactive`(NodeJS 绑定)中,`EnvType` 参数在函数定义里是未命名的,但在函数体中使用了 `env`,这将无法编译——请为该参数添加一个名称(例如 `maajs::EnvType env`),以与使用方式保持一致。
-`!task_runner_->pending()` 时,`Tasker::run_task` 中调用 `controller_->post_inactive()` 的逻辑,可能会与紧接在检查之后入队的新任务产生竞争;建议澄清预期语义,或将“变为 inactive”的状态转换与 runner 状态绑定得更紧密,以避免在仍有任务正在被调度时短暂地将 controller 标记为 inactive。

## Individual Comments

### Comment 1
<location path="source/binding/NodeJS/src/apis/controller.cpp" line_range="218-220" />
<code_context>
     return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
 }

+maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)
+{
+    auto id = MaaControllerPostInactive(controller);
+    return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** post_inactive 的实现使用了 `env`,但参数未命名,这会导致无法编译。

该函数声明了一个没有名称的 `maajs::EnvType` 参数,但在 `ExtContext::get(env)` 中使用了 `env`,这将无法编译。请为该参数命名,并与声明保持一致,例如:

```cpp
maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType env)
{
    auto id = MaaControllerPostInactive(controller);
    return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
}
```
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的审查有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续审查。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In ControllerImpl::post_inactive (NodeJS binding), the EnvType parameter is unnamed in the definition but env is used in the body, which will not compile—give the parameter a name (e.g. maajs::EnvType env) to match the usage.
  • The Tasker::run_task logic that posts controller_->post_inactive() when !task_runner_->pending() may race with new tasks being queued immediately after the check; consider clarifying the intended semantics or tying the inactive transition more tightly to the runner state to avoid transiently marking the controller inactive while work is still being scheduled.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ControllerImpl::post_inactive` (NodeJS binding), the `EnvType` parameter is unnamed in the definition but `env` is used in the body, which will not compile—give the parameter a name (e.g. `maajs::EnvType env`) to match the usage.
- The `Tasker::run_task` logic that posts `controller_->post_inactive()` when `!task_runner_->pending()` may race with new tasks being queued immediately after the check; consider clarifying the intended semantics or tying the inactive transition more tightly to the runner state to avoid transiently marking the controller inactive while work is still being scheduled.

## Individual Comments

### Comment 1
<location path="source/binding/NodeJS/src/apis/controller.cpp" line_range="218-220" />
<code_context>
     return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
 }

+maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)
+{
+    auto id = MaaControllerPostInactive(controller);
+    return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** The post_inactive implementation uses `env` but the parameter is unnamed, which will not compile.

This function declares `maajs::EnvType` without a name but then uses `env` in `ExtContext::get(env)`, which won’t compile. Please name the parameter and keep it consistent with the declaration, e.g.:

```cpp
maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType env)
{
    auto id = MaaControllerPostInactive(controller);
    return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
}
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new controller-wide inactive operation to restore normal window and input states, particularly for Win32 controllers. The feature enables graceful cleanup by reverting pseudo-minimize effects, removing window topmost status, and unblocking user input when tasks complete. The implementation extends across the entire stack from core control units through language bindings to test coverage.

Changes:

  • Added inactive() method to ControlUnitAPI interface and MaaController, implemented across all control unit types (Win32 performs cleanup; others are no-ops)
  • Enhanced Tasker to automatically call post_inactive() when tasks complete and no pending tasks remain
  • Extended agent/client messaging protocol and remote controller to support inactive operations end-to-end
  • Exposed inactive functionality through Python and NodeJS bindings with comprehensive test coverage

Reviewed changes

Copilot reviewed 46 out of 47 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
source/include/ControlUnit/ControlUnitAPI.h Added inactive() pure virtual method to ControlUnitAPI base interface
source/include/Common/MaaTypes.h Added post_inactive() to MaaController interface
include/MaaFramework/Instance/MaaController.h Public C API declaration for MaaControllerPostInactive with documentation
include/MaaFramework/Instance/MaaCustomController.h Added inactive callback to MaaCustomControllerCallbacks struct
source/MaaWin32ControlUnit/Screencap/PseudoMinimizeHelper.h Made revert_pseudo_minimize() public for inactive support
source/MaaWin32ControlUnit/Screencap/*WithPseudoMinimizeScreencap.h Implemented inactive() to revert pseudo-minimize state
source/MaaWin32ControlUnit/Input/*.{h,cpp} Implemented inactive() for all Win32 input methods (Seize, Message, LegacyEvent)
source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.{h,cpp} Orchestrates inactive() calls across screencap and input units
source/MaaWin32ControlUnit/Base/UnitBase.h Added default no-op inactive() to ScreencapBase and InputBase
source/MaaControlUnit/Manager/.{h,cpp} Implemented no-op inactive() for ADB, PlayCover, Gamepad, Dbg, and Custom control units
source/MaaFramework/Controller/ControllerAgent.{h,cpp} Added post_inactive() and handle_inactive() with Action::Type::inactive
source/MaaFramework/Tasker/Tasker.cpp Auto-calls controller->post_inactive() after task completion if no pending tasks
source/MaaFramework/Base/AsyncRunner.hpp Added pending() method to check for queued items
source/include/MaaAgent/Message.hpp Added ControllerPostInactiveReverseRequest/Response message types
source/MaaAgentServer/RemoteInstance/RemoteController.{h,cpp} Implemented post_inactive() for remote controllers
source/MaaAgentClient/Client/AgentClient.{h,cpp} Added handler for controller inactive reverse requests
source/binding/Python/maa/define.py Added InactiveFunc to MaaCustomControllerCallbacks
source/binding/Python/maa/controller.py Added post_inactive() method with documentation and custom controller support
source/binding/NodeJS/src/apis/controller.{h,d.ts,cpp} Added post_inactive() to controller API and TypeScript definitions
source/modules/MaaFramework.cppm Exported MaaControllerPostInactive symbol
source/Common/MaaController.cpp Implemented C API wrapper MaaControllerPostInactive
test/python/binding_test.py Added post_inactive() tests for regular and custom controllers
test/nodejs/binding.ts Added post_inactive() tests for regular and custom controllers
test/agent/agent_child_test.py Added post_inactive() test for agent scenarios

@MistEO
Copy link
Member Author

MistEO commented Feb 27, 2026

@sourcery-ai summary

@MistEO
Copy link
Member Author

MistEO commented Feb 27, 2026

@sourcery-ai review

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并留下了一些总体反馈:

  • AsyncRunner::pending 中,如果只检查队列是否为空,可能会遗漏正在执行中的 action;如果 Tasker::run_task 的意图是在完全没有剩余工作时才 post inactive,建议同时考虑当前的 running_ 状态(例如使用 pending() || running())。
  • ControllerImpl::post_inactive(NodeJS 绑定)中,实现使用了 ExtContext::get(env),但函数签名中并没有为 EnvType 参数命名(当前为 maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)),这样将无法通过编译;请更新函数签名,使其接受并使用一个命名为 env 的参数,就像其他方法中所做的那样。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `AsyncRunner::pending`, only checking whether the queue is empty may miss an in‑flight action; if the intent in `Tasker::run_task` is to post `inactive` only when there is no more work at all, consider also taking the current `running_` state into account (e.g. `pending() || running()`).
- In `ControllerImpl::post_inactive` (NodeJS binding), the implementation uses `ExtContext::get(env)` but the function signature does not name the `EnvType` parameter (currently `maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)`), which will not compile; update the signature to accept and use a named `env` parameter as done in other methods.

## Individual Comments

### Comment 1
<location path="source/binding/NodeJS/src/apis/controller.cpp" line_range="218-220" />
<code_context>
     return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
 }

+maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)
+{
+    auto id = MaaControllerPostInactive(controller);
+    return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** The `post_inactive` implementation uses `env` but the parameter is unnamed, which will not compile.

In `ControllerImpl::post_inactive`, the second parameter is declared as an unnamed `maajs::EnvType`, but the body uses `env`, which is undefined and will cause a compile error. Name the parameter (e.g. `maajs::EnvType env`) so it matches the usage and the header declaration.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In AsyncRunner::pending, only checking whether the queue is empty may miss an in‑flight action; if the intent in Tasker::run_task is to post inactive only when there is no more work at all, consider also taking the current running_ state into account (e.g. pending() || running()).
  • In ControllerImpl::post_inactive (NodeJS binding), the implementation uses ExtContext::get(env) but the function signature does not name the EnvType parameter (currently maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)), which will not compile; update the signature to accept and use a named env parameter as done in other methods.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `AsyncRunner::pending`, only checking whether the queue is empty may miss an in‑flight action; if the intent in `Tasker::run_task` is to post `inactive` only when there is no more work at all, consider also taking the current `running_` state into account (e.g. `pending() || running()`).
- In `ControllerImpl::post_inactive` (NodeJS binding), the implementation uses `ExtContext::get(env)` but the function signature does not name the `EnvType` parameter (currently `maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)`), which will not compile; update the signature to accept and use a named `env` parameter as done in other methods.

## Individual Comments

### Comment 1
<location path="source/binding/NodeJS/src/apis/controller.cpp" line_range="218-220" />
<code_context>
     return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
 }

+maajs::ValueType ControllerImpl::post_inactive(maajs::ValueType self, maajs::EnvType)
+{
+    auto id = MaaControllerPostInactive(controller);
+    return maajs::CallCtorHelper(ExtContext::get(env)->jobCtor, self, id);
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** The `post_inactive` implementation uses `env` but the parameter is unnamed, which will not compile.

In `ControllerImpl::post_inactive`, the second parameter is declared as an unnamed `maajs::EnvType`, but the body uses `env`, which is undefined and will cause a compile error. Name the parameter (e.g. `maajs::EnvType env`) so it matches the usage and the header declaration.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@MistEO
Copy link
Member Author

MistEO commented Feb 27, 2026

@sourcery-ai title

@sourcery-ai sourcery-ai bot changed the title feat: controller inactive Add controller inactive action to restore window/input state Feb 27, 2026
@MistEO MistEO changed the title Add controller inactive action to restore window/input state feat: Add controller inactive action to restore window/input state Feb 27, 2026
@MistEO MistEO merged commit d1a06bf into main Feb 27, 2026
14 checks passed
@MistEO MistEO deleted the feat/inactive branch February 27, 2026 08:41
@ZeroAd-06
Copy link
Contributor

@ZeroAd-06 佬也帮忙瞅瞅恢复部分有没有问题

看起来没什么问题。
其实我也不太懂这些的,代码都是让ai写的

@ZeroAd-06
Copy link
Contributor

@MistEO 此外我们可能需要暴露一个单独取消激活键鼠控制器的api,或者我可能会加一些看起来很奇怪的参数,用来实现终末地的后台wasd(这东西实在是诡异)
这些交给我吧,只是在这里说一下

moomiji added a commit to MaaXYZ/MaaFramework.Binding.CSharp that referenced this pull request Mar 8, 2026
moomiji added a commit to MaaXYZ/MaaFramework.Binding.CSharp that referenced this pull request Mar 8, 2026
moomiji added a commit to MaaXYZ/MaaFramework.Binding.CSharp that referenced this pull request Mar 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants