feat(controller): add MaaControllerPostMouseMoveRelative#1189
Conversation
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并留下了一些高层次的反馈:
- 在 Python 绑定中,
CustomController.mouse_move_relative是一个新的抽象方法(必需),而在 NodeJS 的CustomControllerActor中它是可选的(mouse_move_relative?);建议统一这两边的语义,以便不同语言的自定义控制器作者在要求和失败模式上保持一致。 - 对于
ControlUnitAPI::mouse_move_relative和InputBase::mouse_move_relative,你目前默认返回false;如果不希望静默地“不支持但不报错”,可以考虑打印一个警告日志,或者让调用方显式检查特性支持情况,从而更容易暴露误用问题。
面向 AI Agent 的提示
Please address the comments from this code review:
## Overall Comments
- In the Python binding, `CustomController.mouse_move_relative` is a new abstract method (mandatory), while in the NodeJS `CustomControllerActor` it is optional (`mouse_move_relative?`); consider aligning these semantics so that custom-controller authors in different languages have consistent requirements and failure modes.
- For `ControlUnitAPI::mouse_move_relative` and `InputBase::mouse_move_relative`, you currently return `false` by default; if silent unsupported behavior is undesirable, consider logging a warning or making callers explicitly check feature support so that misuse is more easily surfaced.
## Individual Comments
### Comment 1
<location path="source/binding/Python/maa/controller.py" line_range="1383-1398" />
<code_context>
return int(self.touch_up(int(c_contact)))
+ @staticmethod
+ @MaaCustomControllerCallbacks.MouseMoveRelativeFunc
+ def _c_mouse_move_relative_agent(
+ c_dx: ctypes.c_int32,
+ c_dy: ctypes.c_int32,
+ trans_arg: ctypes.c_void_p,
+ ) -> int:
+ if not trans_arg:
+ return int(False)
+
+ self: CustomController = ctypes.cast(
+ trans_arg,
+ ctypes.py_object,
+ ).value
+
+ return int(self.mouse_move_relative(int(c_dx), int(c_dy)))
+
@staticmethod
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 在跨越 C 边界之前,考虑对 mouse_move_relative 回调添加针对 Python 异常的保护
如果 `mouse_move_relative` 抛出异常,该异常会通过 C 回调向下传播,并可能导致原生崩溃或未定义行为。请用 try/except 包裹这次调用,记录 traceback,并在失败时返回 `False`,以保证 FFI 边界的安全性,并与健壮的 C API 实践保持一致。
```suggestion
@staticmethod
@MaaCustomControllerCallbacks.MouseMoveRelativeFunc
def _c_mouse_move_relative_agent(
c_dx: ctypes.c_int32,
c_dy: ctypes.c_int32,
trans_arg: ctypes.c_void_p,
) -> int:
if not trans_arg:
return int(False)
self: CustomController = ctypes.cast(
trans_arg,
ctypes.py_object,
).value
import logging
try:
return int(self.mouse_move_relative(int(c_dx), int(c_dy)))
except Exception:
logging.exception("Unhandled exception in CustomController.mouse_move_relative callback")
return int(False)
```
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈来改进后续的评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- In the Python binding,
CustomController.mouse_move_relativeis a new abstract method (mandatory), while in the NodeJSCustomControllerActorit is optional (mouse_move_relative?); consider aligning these semantics so that custom-controller authors in different languages have consistent requirements and failure modes. - For
ControlUnitAPI::mouse_move_relativeandInputBase::mouse_move_relative, you currently returnfalseby default; if silent unsupported behavior is undesirable, consider logging a warning or making callers explicitly check feature support so that misuse is more easily surfaced.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the Python binding, `CustomController.mouse_move_relative` is a new abstract method (mandatory), while in the NodeJS `CustomControllerActor` it is optional (`mouse_move_relative?`); consider aligning these semantics so that custom-controller authors in different languages have consistent requirements and failure modes.
- For `ControlUnitAPI::mouse_move_relative` and `InputBase::mouse_move_relative`, you currently return `false` by default; if silent unsupported behavior is undesirable, consider logging a warning or making callers explicitly check feature support so that misuse is more easily surfaced.
## Individual Comments
### Comment 1
<location path="source/binding/Python/maa/controller.py" line_range="1383-1398" />
<code_context>
return int(self.touch_up(int(c_contact)))
+ @staticmethod
+ @MaaCustomControllerCallbacks.MouseMoveRelativeFunc
+ def _c_mouse_move_relative_agent(
+ c_dx: ctypes.c_int32,
+ c_dy: ctypes.c_int32,
+ trans_arg: ctypes.c_void_p,
+ ) -> int:
+ if not trans_arg:
+ return int(False)
+
+ self: CustomController = ctypes.cast(
+ trans_arg,
+ ctypes.py_object,
+ ).value
+
+ return int(self.mouse_move_relative(int(c_dx), int(c_dy)))
+
@staticmethod
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Consider guarding mouse_move_relative callback against Python exceptions before crossing the C boundary
If `mouse_move_relative` raises, the exception will propagate through the C callback and can cause native crashes or undefined behavior. Please wrap this call in a try/except, log the traceback, and return `False` on failure to keep the FFI boundary safe and consistent with robust C API practices.
```suggestion
@staticmethod
@MaaCustomControllerCallbacks.MouseMoveRelativeFunc
def _c_mouse_move_relative_agent(
c_dx: ctypes.c_int32,
c_dy: ctypes.c_int32,
trans_arg: ctypes.c_void_p,
) -> int:
if not trans_arg:
return int(False)
self: CustomController = ctypes.cast(
trans_arg,
ctypes.py_object,
).value
import logging
try:
return int(self.mouse_move_relative(int(c_dx), int(c_dy)))
except Exception:
logging.exception("Unhandled exception in CustomController.mouse_move_relative callback")
return int(False)
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| @staticmethod | ||
| @MaaCustomControllerCallbacks.MouseMoveRelativeFunc | ||
| def _c_mouse_move_relative_agent( | ||
| c_dx: ctypes.c_int32, | ||
| c_dy: ctypes.c_int32, | ||
| trans_arg: ctypes.c_void_p, | ||
| ) -> int: | ||
| if not trans_arg: | ||
| return int(False) | ||
|
|
||
| self: CustomController = ctypes.cast( | ||
| trans_arg, | ||
| ctypes.py_object, | ||
| ).value | ||
|
|
||
| return int(self.mouse_move_relative(int(c_dx), int(c_dy))) |
There was a problem hiding this comment.
suggestion (bug_risk): 在跨越 C 边界之前,考虑对 mouse_move_relative 回调添加针对 Python 异常的保护
如果 mouse_move_relative 抛出异常,该异常会通过 C 回调向下传播,并可能导致原生崩溃或未定义行为。请用 try/except 包裹这次调用,记录 traceback,并在失败时返回 False,以保证 FFI 边界的安全性,并与健壮的 C API 实践保持一致。
| @staticmethod | |
| @MaaCustomControllerCallbacks.MouseMoveRelativeFunc | |
| def _c_mouse_move_relative_agent( | |
| c_dx: ctypes.c_int32, | |
| c_dy: ctypes.c_int32, | |
| trans_arg: ctypes.c_void_p, | |
| ) -> int: | |
| if not trans_arg: | |
| return int(False) | |
| self: CustomController = ctypes.cast( | |
| trans_arg, | |
| ctypes.py_object, | |
| ).value | |
| return int(self.mouse_move_relative(int(c_dx), int(c_dy))) | |
| @staticmethod | |
| @MaaCustomControllerCallbacks.MouseMoveRelativeFunc | |
| def _c_mouse_move_relative_agent( | |
| c_dx: ctypes.c_int32, | |
| c_dy: ctypes.c_int32, | |
| trans_arg: ctypes.c_void_p, | |
| ) -> int: | |
| if not trans_arg: | |
| return int(False) | |
| self: CustomController = ctypes.cast( | |
| trans_arg, | |
| ctypes.py_object, | |
| ).value | |
| import logging | |
| try: | |
| return int(self.mouse_move_relative(int(c_dx), int(c_dy))) | |
| except Exception: | |
| logging.exception("Unhandled exception in CustomController.mouse_move_relative callback") | |
| return int(False) |
Original comment in English
suggestion (bug_risk): Consider guarding mouse_move_relative callback against Python exceptions before crossing the C boundary
If mouse_move_relative raises, the exception will propagate through the C callback and can cause native crashes or undefined behavior. Please wrap this call in a try/except, log the traceback, and return False on failure to keep the FFI boundary safe and consistent with robust C API practices.
| @staticmethod | |
| @MaaCustomControllerCallbacks.MouseMoveRelativeFunc | |
| def _c_mouse_move_relative_agent( | |
| c_dx: ctypes.c_int32, | |
| c_dy: ctypes.c_int32, | |
| trans_arg: ctypes.c_void_p, | |
| ) -> int: | |
| if not trans_arg: | |
| return int(False) | |
| self: CustomController = ctypes.cast( | |
| trans_arg, | |
| ctypes.py_object, | |
| ).value | |
| return int(self.mouse_move_relative(int(c_dx), int(c_dy))) | |
| @staticmethod | |
| @MaaCustomControllerCallbacks.MouseMoveRelativeFunc | |
| def _c_mouse_move_relative_agent( | |
| c_dx: ctypes.c_int32, | |
| c_dy: ctypes.c_int32, | |
| trans_arg: ctypes.c_void_p, | |
| ) -> int: | |
| if not trans_arg: | |
| return int(False) | |
| self: CustomController = ctypes.cast( | |
| trans_arg, | |
| ctypes.py_object, | |
| ).value | |
| import logging | |
| try: | |
| return int(self.mouse_move_relative(int(c_dx), int(c_dy))) | |
| except Exception: | |
| logging.exception("Unhandled exception in CustomController.mouse_move_relative callback") | |
| return int(False) |
|
目前可以参考 post shell (adb 的),如果不是 win32 控制器就报错 |
| class Win32ControlUnitAPI : public ControlUnitAPI | ||
| { | ||
| public: | ||
| virtual ~Win32ControlUnitAPI() = default; |
There was a problem hiding this comment.
这样的话,其他 control unit 可以直接不用定义这个函数,ControlUnitAPI 里的空实现可以删掉,以保持纯虚

本 PR 旨在为 controller 层补充一个新的基础输入能力:相对鼠标移动。
背景
当前框架已经提供了较为完整的控制接口,例如:
这些接口对于点击、拖拽、移动到某个位置、键盘操作等场景都很好用,尤其适合以 绝对坐标 为核心的交互方式。
不过在一些 3D 游戏或自由视角场景里,业务层需要表达的并不是“把指针移动到某个点”,而是:
也就是一种 relative delta 语义,而不是 absolute position 语义。
关于为什么需要补充这个接口?
在现有接口下,如果业务层要实现“相对移动”的效果,理论上也可以通过“记录当前位置、再换算目标点”的方式,用 post_touch_move 去模拟。这种方式在一些简单场景下是可行的。
但对于 3D 镜头控制这类持续、增量式输入来说,业务层通常还需要额外处理一系列复杂问题:
也就是说,在这类场景下,现有
absolute move接口并不是单纯“写起来绕一点”,而是很难长期稳定地表达镜头控制所需的连续相对位移。这些逻辑放在业务层并不是完全做不到,只是它们和“业务策略”本身关系不大,更像是在弥补 controller 层缺少的一种基础输入语义。
如果没有这一层原生能力,业务实现往往会不断堆积额外的状态维护和补偿逻辑,最终让问题从“控制业务”变成“维护输入模拟本身”。
换句话说,这里缺的不是一个“更方便的 helper”,而是一种更适合这类场景的原生功能:
本 PR 做了什么
本 PR 新增了一个核心接口:
MaaControllerPostMouseMoveRelative(MaaController* ctrl, int32_t dx, int32_t dy)
它的语义非常直接:
Win32 controller中提供原生实现。与现有接口的关系
这个接口不是为了替代 post_touch_move,而是补充另一种输入语义。可以简单对比理解为:
两者解决的问题不一样,各自有适合的场景:
期望效果
希望补上这个接口之后,controller 层能够同时覆盖两类常见输入方式:
这样业务层在面对不同输入模型时,都能选择更贴近实际语义的接口,而不再需要额外承担过多的状态补偿与模拟逻辑。
Summary by Sourcery
通过核心框架、Win32 控制单元、远程/代理层以及语言绑定新增并贯通用于相对鼠标移动的控制器 API。
新特性:
MaaControllerPostMouseMoveRelativeAPI,用于通过控制器抽象层投递相对鼠标移动动作。增强:
mouse_move_relative动作。文档:
MaaControllerPostMouseMoveRelativeAPI。测试:
Original summary in English
Summary by Sourcery
Add a new controller API for relative mouse movement and wire it through the core framework, Win32 control unit, remote/agent layers, and language bindings.
New Features:
Enhancements:
Documentation:
Tests: