2.4 控制方式说明
本文档详细说明 MaaFramework 中 Screencap(截图)和 Input(控制)的各种方式及其配置。
TIP
- 对于 API ,screencap/input 使用
int类型(按位或组合);对于 ProjectInterface V2,使用string类型(直接使用名称)。 - ProjectInterface V2 支持配置 Win32、MacOS、Linux 等控制器的 screencap/input 控制方式。Adb 控制器的 screencap/input 使用
MaaToolkitAdbDeviceFind自动检测和选择最优方式,无需手动配置。
Adb
Adb Input
参考 MaaDef.h
将下面选择的方式 按位或 合并为一个值提供。MaaFramework 将会按照固定优先级顺序尝试所有提供的方式,选择首个可用方式。
默认尝试除 EmulatorExtras 外所有方式。
优先级: EmulatorExtras > Maatouch > MinitouchAndAdbKey > AdbShell
| 名称 | API 值 | 速度 | 兼容性 | 说明 |
|---|---|---|---|---|
| AdbShell | 1 | 慢 | 高 | |
| MinitouchAndAdbKey | 2 | 快 | 中 | 按键仍使用 AdbShell |
| Maatouch | 4 | 快 | 中 | |
| EmulatorExtras | 8 | 快 | 低 | 仅支持模拟器:MuMu 12、腾讯应用宝 |
Adb Screencap
参考 MaaDef.h
将下面选择的方式 按位或 合并为一个值提供。MaaFramework 将会尝试所有提供的方式,选择最快的可用方式。
默认尝试除 RawByNetcat,MinicapDirect,MinicapStream 外所有方式。
MinicapDirect 和 MinicapStream 由于会编码为 jpg,为有损编码,将显著降低模板匹配的效果,不建议使用。
| 名称 | API 值 | 速度 | 兼容性 | 编码 | 说明 |
|---|---|---|---|---|---|
| EncodeToFileAndPull | 1 | 慢 | 高 | 无损 | |
| Encode | 2 | 慢 | 高 | 无损 | |
| RawWithGzip | 4 | 中 | 高 | 无损 | |
| RawByNetcat | 8 | 快 | 低 | 无损 | |
| MinicapDirect | 16 | 快 | 低 | 有损 | |
| MinicapStream | 32 | 极快 | 低 | 有损 | |
| EmulatorExtras | 64 | 极快 | 低 | 无损 | 仅支持模拟器:MuMu 12、雷电 9、AVD、腾讯应用宝 |
Android Native
Android Native 控制器用于在 Android 环境下通过 MaaAndroidNativeControlUnit 直接完成截图和输入。
Android Native 前置要求
- 仅支持 Android 平台
Android Native 配置
通过 MaaAndroidNativeControllerCreate(config_json) 传入 JSON 配置:
library_path:Android Native 控制单元库路径screen_resolution.width/screen_resolution.height:原始截图分辨率,同时也是 touch 坐标系display_id:目标显示 ID,可选,默认0force_stop:start_app前是否强制停止应用,可选,默认false
NOTE
MaaFramework 会在 ControllerAgent 中统一把缩放后的识别坐标换算回原始截图坐标。
Android Native 控制器不会再额外做 frame-to-touch 映射,只会按 screen_resolution 做边界裁剪。
如果控制单元返回的原始截图分辨率与 screen_resolution 不一致,截图会直接失败。
Android Native 输入
支持多指触控。contact 为手指编号(0 为第一根手指,取值 0–15,对应 Android MotionEvent pointer id)。Click / LongPress / Swipe / MultiSwipe / TouchDown / TouchMove / TouchUp 可通过不同 contact 区分手指。
NOTE
外部控制单元库的 TouchArgs 必须包含 contact 字段,否则多指事件无法正确送达。pressure 当前不会传递给外部库。
Win32
Win32 Input
参考 MaaDef.h
选择下面的值提供。
无默认值。Client 可以选择一个作为默认值。
Win32 下不同程序处理输入的方法不同,不存在一个通用方式。
| 名称 | API 值 | 兼容性 | 需管理员权限 | 抢占鼠标 | 支持后台 | 说明 |
|---|---|---|---|---|---|---|
| Seize | 1 | 高 | 否 | 是 | 否 | |
| SendMessage | 2 | 中 | 可能 | 否 | 是 | |
| PostMessage | 4 | 中 | 可能 | 否 | 是 | |
| LegacyEvent | 8 | 低 | 否 | 是 | 否 | |
| PostThreadMessage | 16 | 低 | 可能 | 否 | 是 | 已废弃 |
| SendMessageWithCursorPos | 32 | 中 | 可能 | 短暂 | 是 | 短暂移动光标到目标位置后恢复,专为检测实际鼠标位置的程序设计 |
| PostMessageWithCursorPos | 64 | 中 | 可能 | 短暂 | 是 | 短暂移动光标到目标位置后恢复,专为检测实际鼠标位置的程序设计 |
| SendMessageWithWindowPos | 128 | 中 | 可能 | 否 | 是 | 短暂移动窗口使目标位置与光标重合后恢复,不抢占鼠标 |
| PostMessageWithWindowPos | 256 | 中 | 可能 | 否 | 是 | 短暂移动窗口使目标位置与光标重合后恢复,不抢占鼠标 |
| Interception | 512 | 中 | 是 | 否 | 否 | 通过 Interception 驱动注入鼠标和键盘事件,适用于常规 Win32 注入不生效的场景 |
| AnchoredTouch | 1024 | 中 | 可能 | 否 | 是 | 注入合成触控接触点,目标窗口收到 WM_POINTER 系列消息,仅支持鼠标 |
NOTE
- 管理员权限主要取决于目标程序的权限级别,若目标程序为管理员权限,则需以管理员权限运行以保证兼容性。
WithCursorPos系列方式会短暂移动光标到目标位置,发送完消息后会将光标移回原位置,因此会“短暂”抢占鼠标,但不会阻止用户操作。WithWindowPos系列方式会短暂移动窗口,使目标位置与当前光标位置重合,发送完消息后会将窗口移回原位置。不会移动光标,因此不抢占鼠标,但窗口会短暂闪烁。Interception需要正确安装 Interception 驱动,且通常需要与目标程序相同或更高的权限级别。Interception的鼠标与按键操作通过驱动发送;文本输入仍通过系统 UnicodeSendInput发送,不走 Interception 驱动路径。AnchoredTouch通过InjectSyntheticPointerInput注入合成触控接触点,需要 Windows 10 1809 及以上。全程不移动光标、不改变前台窗口,因此不影响用户对其他窗口的操作,对随光标位置绘制画面的程序也不产生偏差。代价是目标窗口本身在被遮挡时会有短暂的可见变化,详见下条。AnchoredTouch只实现点击与滑动。键盘操作请在键盘方式中另选,scroll则没有替代方案:滚轮操作只走鼠标方式,而合成触控设备无法表达滚轮,因此需要滚轮的场景请整体改用其他输入方式。- 合成指针的命中判定只认桌面当前的 Z 序,因此
AnchoredTouch在目标点被遮挡时会将目标窗口临时提升到最上层并降到最低分层透明度,所有接触点抬起后立即恢复原有 Z 序与透明度。目标窗口部分可见时,每次操作可见部分会闪烁约 70ms。提升未能生效时该次操作直接失败,不会把输入注入到遮挡它的窗口上。 - 提升需要为目标窗口添加
WS_EX_LAYERED扩展样式,该样式在首次需要提升时添加,每次提升前重新确认,并在控制器空闲或调用inactive时清除,清除时若该分层状态正被其他模块使用则予以保留;目标点从未被遮挡时不会改动目标窗口的任何状态。若该样式无法维持或不透明度无法压低,该次操作直接失败,不会将目标窗口以完全可见的状态提到最前。目标窗口若通过UpdateLayeredWindow实现分层,AnchoredTouch会拒绝提升它,以免破坏其绘制。文档规定WS_EX_LAYERED不能用于CS_OWNDC或CS_CLASSDC窗口类,但该限制并不总是成立(Unity 窗口带CS_OWNDC,实测可用),因此命中该条件时仅给出告警,实际以 API 返回值为准。 AnchoredTouch不支持最小化的目标窗口,该次操作直接报错返回:最小化窗口的客户区不在屏幕上,提升也改变不了这一点。选用FramePool/PrintWindow截图方式时窗口在每次截图前会被转出最小化状态,因此不会触发;选用其他截图方式时最小化窗口本身也无法截图。另需注意这两种截图方式的伪最小化在inactive时只恢复样式与不透明度,不重新最小化窗口。- 借用期间还会临时移除
WS_EX_TRANSPARENT,该样式会使输入穿透到下层窗口,还原时原样加回。由于截图侧的伪最小化会改写同一个窗口的扩展样式与不透明度,AnchoredTouch在归还前会核对这些属性是否仍与借用时写入的一致,不一致则视为已被其他模块接管而放弃写回,以免覆盖对方刚设好的状态。该核对无法完全消除两侧动作交错的时间窗口。 - Interception 键盘选择会排除没有硬件 ID 的槽位。自动选择会保留仍然连接的键盘,绑定失效后选取编号最小的已连接槽位;这不等于识别用户最后操作的键盘。多键盘环境下,可在启动宿主程序前设置环境变量
MAA_INTERCEPTION_KEYBOARD_DEVICE,指定从零开始的槽位编号(0–9),或设备初始化日志中报告的第一个完整硬件 ID。硬件 ID 可跟随键盘的槽位变化,但同型号设备可能共享 ID。明确指定的设备不可用时返回失败,不会静默改用其他键盘。 - 发送输入前会重新确认键盘是否连接。控制器仍有按键未释放时,设备选择变更会推迟到全部释放之后;若期间键盘断开,释放操作会失败,不会向替代设备发送释放事件。输入失败后应停止或重新连接控制器。驱动写入成功本身不代表目标程序已经处理输入。
- Win32 还提供了鼠标锁定跟随模式(Mouse Lock Follow):通过
MaaControllerSetOption(ctrl, MaaCtrlOption_MouseLockFollow, &enabled, sizeof(bool))开启(enabled为true开启,false关闭),适用于 TPS/FPS 等在后台将鼠标锁定到窗口内的游戏。开启后窗口会始终跟随鼠标移动,同时通过 RawInput 对冲阻止游戏感知硬件鼠标位移。配合MaaControllerPostRelativeMove可在此模式下注入视角旋转。注意: Win32 平台的MaaControllerPostRelativeMove需要先开启鼠标锁定跟随模式,否则调用将失败。仅支持 MessageInput 系列输入方式(SendMessage / PostMessage 及其变体)。 - Win32 还提供了后台受管键守护(Background Managed Keys):通过
MaaControllerSetOption(ctrl, MaaCtrlOption_BackgroundManagedKeys, keycodes, sizeof(int32_t) * count)声明需要接管的虚拟键码数组。声明成功后,命中的按键操作自动走后台守护路径,并在控制器空闲时持续修正按键状态。
Win32 Screencap
参考 MaaDef.h
将下面选择的方式 按位或 合并为一个值提供。MaaFramework 将会尝试所有提供的方式,选择最快的可用方式。
无默认值。Client 可以选择一个组合作为默认值。
Win32 下不同程序处理绘制的方法不同,不存在一个通用方式。
| 名称 | API 值 | 速度 | 兼容性 | 需管理员权限 | 支持后台 | 说明 |
|---|---|---|---|---|---|---|
| GDI | 1 | 快 | 中 | 否 | 否 | |
| FramePool | 2 | 极快 | 中 | 否 | 是 | Windows 10 1903+ 可用 |
| DXGI_DesktopDup | 4 | 极快 | 低 | 否 | 否 | 桌面复制(全屏输出复制) |
| DXGI_DesktopDup_Window | 8 | 极快 | 低 | 否 | 否 | 桌面复制后裁剪 |
| PrintWindow | 16 | 中 | 中 | 否 | 是 | |
| ScreenDC | 32 | 快 | 高 | 否 | 否 |
NOTE
提供了三个组合宏便于直接使用:
MaaWin32ScreencapMethod_All:所有截图方式MaaWin32ScreencapMethod_Foreground:DXGI_DesktopDup_Window | ScreenDCMaaWin32ScreencapMethod_Background:FramePool | PrintWindow
FramePool 和 PrintWindow 内置了伪最小化支持:当目标窗口被最小化时,会将窗口设为透明并开启点击穿透,以不激活的方式恢复窗口,从而在不打扰用户的情况下继续截图。
其他截图方式在窗口最小化后无法获取有效内容,请避免窗口最小化。
MacOS
MacOS 控制器用于在 macOS 上控制原生 macOS 应用程序。
MacOS 前置要求
- macOS 14.0 及以上版本
- 需要授予以下权限:
- 录屏权限 (Screen Recording):用于截图功能
- 辅助功能权限 (Accessibility):用于输入控制功能
权限调试
如果遇到权限相关问题,可以通过以下命令重置权限:
# 重置录屏权限
tccutil reset ScreenCapture
# 重置辅助功能权限
tccutil reset AccessibilityTIP
重置权限后需要重新启动应用程序,并重新授予权限。
TIP
MaaFramework 不负责权限申请和引导,Client需要自行实现相关功能。MaaToolkit 中提供了部分辅助函数,可以参考 test/macos_test
MacOS Screencap
参考 MaaDef.h
选择下面的值提供。
无默认值。Client 可以选择一个作为默认值。
| 名称 | API 值 | 速度 | 兼容性 | 需权限 | 支持后台 | 说明 |
|---|---|---|---|---|---|---|
| ScreenCaptureKit | 1 | 快 | 高 | 录屏权限 | 是 | 需要 macOS 14.0+ |
MacOS Input
参考 MaaDef.h
选择下面的值提供。
无默认值。Client 可以选择一个作为默认值。
| 名称 | API 值 | 兼容性 | 需权限 | 支持后台 | 说明 |
|---|---|---|---|---|---|
| GlobalEvent | 1 | 高 | 辅助功能权限 | 否 | 通过 CGEventPost(kCGHIDEventTap) 向全局 HID 事件流注入,由系统分发至前台窗口(会自动激活目标窗口) |
| PostToPid | 2 | 中 | 辅助功能权限 | 是 | 通过 CGEventPostToPid 直接发送至目标进程,无需目标窗口处于前台 |
NOTE
- 截图:ScreenCaptureKit 支持后台截图,包括其他 Space 中的全屏窗口,无需目标窗口处于前台。不支持台前调度(Stage Manager),截图仅能获取倾斜的缩略小窗,疑似系统 Bug。
- 键盘输入:PostToPid 模式下键盘输入支持后台操作,无需激活目标窗口。
- 鼠标输入:PostToPid 支持后台和全屏输入与点击。但部分游戏(如异环)会在首次点击时检测窗口焦点,若无焦点则抢夺焦点,导致窗口不断跳转前台而无法停止。建议前端提示用户以窗口化模式运行,或提供快捷键停止运行。
PlayCover (macOS)
PlayCover 控制器用于在 macOS 上控制通过 fork版PlayCover 运行的 iOS 应用程序。
PlayCover 前置要求
- 在 macOS 上安装 fork版PlayCover
- 目标 iOS 应用需要在 PlayCover 中启用 MaaTools 功能
Gamepad (Windows)
Gamepad 控制器用于在 Windows 上模拟 Xbox 360 或 DualShock 4 手柄输入,适用于需要手柄控制的游戏。
Gamepad 前置要求
需要安装 ViGEm Bus Driver。
手柄类型
| 类型 | API 值 | 说明 |
|---|---|---|
| Xbox360 | 0 | Microsoft Xbox 360 Controller (有线) |
| DualShock4 | 1 | Sony DualShock 4 Controller (有线) |
操作映射
Gamepad 控制器使用以下映射方式:
数字按键 (click_key/key_down/key_up)
使用 MaaGamepadButton_* 常量作为按键值。Xbox 按键值用于 Xbox360 手柄,DS4 面板按键自动映射到 Xbox 等效按键:
| 按键 | API 值 | Xbox 360 | DualShock 4 等效 |
|---|---|---|---|
| DPAD_UP | 1 | 十字键 上 | 十字键 上 |
| DPAD_DOWN | 2 | 十字键 下 | 十字键 下 |
| DPAD_LEFT | 4 | 十字键 左 | 十字键 左 |
| DPAD_RIGHT | 8 | 十字键 右 | 十字键 右 |
| START / OPTIONS | 16 | Start | Options |
| BACK / SHARE | 32 | Back | Share |
| LEFT_THUMB / L3 | 64 | 左摇杆按下 | L3 |
| RIGHT_THUMB / R3 | 128 | 右摇杆按下 | R3 |
| LB / L1 | 256 | LB | L1 |
| RB / R1 | 512 | RB | R1 |
| GUIDE | 1024 | Xbox Guide | - |
| A / CROSS | 4096 | A | ✗ (Cross) |
| B / CIRCLE | 8192 | B | ○ (Circle) |
| X / SQUARE | 16384 | X | □ (Square) |
| Y / TRIANGLE | 32768 | Y | △ (Triangle) |
| PS | 65536 | - | PS (仅 DS4) |
| TOUCHPAD | 131072 | - | 触摸板按下 (仅 DS4) |
模拟输入 (touch_down/touch_move/touch_up)
使用 contact 参数选择控制目标:
| Contact | 说明 | x/y 范围 | pressure 范围 |
|---|---|---|---|
| 0 | 左摇杆 | -32768 ~ 32767 | 忽略 |
| 1 | 右摇杆 | -32768 ~ 32767 | 忽略 |
| 2 | 左扳机 (LT/L2) | 忽略 | 0 ~ 255 |
| 3 | 右扳机 (RT/R2) | 忽略 | 0 ~ 255 |
NOTE
- 需要安装 ViGEm Bus Driver 才能使用此控制器。
Linux
Linux 控制器用于在 Linux 上控制应用程序。
Linux Screencap
参考 MaaDef.h
选择下面的值提供。
无默认值。Client 可以选择一个作为默认值。
| 名称 | API 值 | 需权限 | 说明 |
|---|---|---|---|
| Wlr | 1 | 否 | 通过 wlr-screencopy-unstable-v1 协议 |
| PipeWire | 4 | 否 | 通过 PipeWire |
TIP
MaaFramework 不负责 Screencast Portal 的处理,Client 需要自行实现相关功能。MaaToolkit 中提供了部分辅助函数,可以参考 test/linux_test
Linux Input
参考 MaaDef.h
选择下面的值提供。
无默认值。Client 可以选择一个作为默认值。
| 名称 | API 值 | 需权限 | 说明 |
|---|---|---|---|
| Wlr | 1 | 否 | 通过 virtual-keyboard-unstable-v1 和 wlr-virtual-pointer-unstable-v1 协议 |
| UInput | 2 | 是 | 通过 /dev/uinput |
| Libei | 4 | 否 | 通过 libei (EIS socket) 注入输入,如 gamescope 提供的 gamescope-<n>-ei |
环境要求
使用 Wlr 截图方式时,wlroots 合成器必须支持以下协议:
- Wayland 核心协议
wlr-screencopy-unstable-v1
使用 Wlr 输入方式时,wlroots 合成器必须支持以下协议:
- Wayland 核心协议
virtual-keyboard-unstable-v1wlr-virtual-pointer-unstable-v1
使用 PipeWire 截图方式时,有两种模式:
- 显示器捕获:传入通过
xdg-desktop-portal取得的合成器 PipeWire FD(pw_socket_fd)和节点 ID(pw_node_id)。 - 会话 daemon 节点捕获:不传 FD,设置
pw_node_id直连会话 PipeWire daemon 上的节点(如 gamescope 的 Video/Source 节点), 节点 ID 可通过MaaToolkitGamescopeInstanceFindAll发现。
在 ProjectInterface V2 中,通过 controller.linux.pipewire_source 字段选择模式:Portal 对应显示器捕获,Gamescope 对应会话 daemon 节点捕获(默认 Gamescope)。
使用 Libei 输入方式时,需要提供 eis_socket_path 指向合成器提供的 EIS socket,例如 gamescope 的 /run/user/<uid>/gamescope-<n>-ei。文本输入需要系统 libei ≥ 1.6.0,Ubuntu 24.04 等旧发行版默认只有 1.2.1,需自行安装新版。
使用 UInput 输入方式时,当前用户必须具有 /dev/uinput 设备的读写权限。
当使用 UInput 输入方式时,建议配置 udev 规则:创建 /etc/udev/rules.d/99-uinput.rules,添加内容 KERNEL=="uinput", MODE="0660", GROUP="input" ,并将当前用户加入 input 组,重启生效。
NOTE
建议启动一个嵌套合成器会话以使用 Wlr 输入方式。不建议控制当前桌面所使用的合成器,这可能会在任务执行过程中产生意外行为。
键盘输入说明
Linux 控制器下,使用 MaaControllerPostKey{Down,Up} 传入的按键默认为 evdev 扫描码,定义见 linux/input-event-codes.h。
如需使用 Win32 Virtual-Key 键码(VK_*),在创建控制器时将 MaaLinuxControllerCreate 参数 config_json 中 use_win32_vk_code 字段置为 true 即可。开启后,MaaControllerPostClickKey / MaaControllerPostKey{Down,Up} 所接受的键码会被视为 Win32 VK 键码并在内部转换为 evdev 码。此开关在创建时一次性决定,不可运行时修改,便于从 Win32 控制器的代码中迁移按键逻辑到 Linux。
NOTE
- 文本输入:通过
MaaControllerPostInputText仅支持 ASCII 字符。
