# 2.4 控制方式说明

本文档详细说明 MaaFramework 中 Screencap（截图）和 Input（控制）的各种方式及其配置。

> [!TIP]
>
> - 对于 API ，screencap/input 使用 `int` 类型（按位或组合）；对于 [ProjectInterface V2](3.3-ProjectInterfaceV2协议.md)，使用 `string` 类型（直接使用名称）。
> - [ProjectInterface V2](3.3-ProjectInterfaceV2协议.md) 仅支持配置 Win32 控制器的 screencap/mouse/keyboard 方式。Adb 控制器的 screencap/input 使用 `MaaToolkitAdbDeviceFind` 自动检测和选择最优方式，无需手动配置。

## Adb

### Adb Input

> 参考 [MaaDef.h](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaDef.h#L267-L294)

将下面选择的方式 **按位或** 合并为一个值提供。MaaFramework 将会按照固定优先级顺序尝试所有提供的方式，选择首个可用方式。

默认尝试除 EmulatorExtras 外所有方式。

> 优先级: EmulatorExtras > Maatouch > MinitouchAndAdbKey > AdbShell

| 名称 | API 值 | 速度 | 兼容性 | 说明 |
| --- | --- | --- | --- | --- |
| AdbShell | `1` | 慢 | 高 | |
| MinitouchAndAdbKey | `2` | 快 | 中 | 按键仍使用 AdbShell |
| Maatouch | `4` | 快 | 中 | |
| EmulatorExtras | `8` | 快 | 低 | 仅支持模拟器：MuMu 12、腾讯应用宝 |

### Adb Screencap

> 参考 [MaaDef.h](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaDef.h#L230-L266)

将下面选择的方式 **按位或** 合并为一个值提供。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 前置要求

1. 仅支持 Android 平台

### Android Native 配置

通过 `MaaAndroidNativeControllerCreate(config_json)` 传入 JSON 配置：

- `library_path`：Android Native 控制单元库路径
- `screen_resolution.width` / `screen_resolution.height`：原始截图分辨率，同时也是 touch 坐标系
- `display_id`：目标显示 ID，可选，默认 `0`
- `force_stop`：`start_app` 前是否强制停止应用，可选，默认 `false`

> [!NOTE]
>
> MaaFramework 会在 `ControllerAgent` 中统一把缩放后的识别坐标换算回原始截图坐标。
> Android Native 控制器不会再额外做 frame-to-touch 映射，只会按 `screen_resolution` 做边界裁剪。
> 如果控制单元返回的原始截图分辨率与 `screen_resolution` 不一致，截图会直接失败。

## Win32

### Win32 Input

> 参考 [MaaDef.h](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaDef.h#L326-L374)

选择下面的值提供。

无默认值。Client 可以选择一个作为默认值。

Win32 下不同程序处理输入的方法不同，不存在一个通用方式。

| 名称 | API 值 | 兼容性 | 需管理员权限 | 抢占鼠标 | 支持后台 | 说明 |
| --- | --- | --- | --- | --- | --- | --- |
| Seize | `1` | 高 | 否 | 是 | 否 | |
| SendMessage | `2` | 中 | 可能 | 否 | 是 | |
| PostMessage | `4` | 中 | 可能 | 否 | 是 | |
| LegacyEvent | `8` | 低 | 否 | 是 | 否 | |
| PostThreadMessage | `16` | 低 | 可能 | 否 | 是 | 已废弃 |
| SendMessageWithCursorPos | `32` | 中 | 可能 | 短暂 | 是 | 短暂移动光标到目标位置后恢复，专为检测实际鼠标位置的程序设计 |
| PostMessageWithCursorPos | `64` | 中 | 可能 | 短暂 | 是 | 短暂移动光标到目标位置后恢复，专为检测实际鼠标位置的程序设计 |
| SendMessageWithWindowPos | `128` | 中 | 可能 | 否 | 是 | 短暂移动窗口使目标位置与光标重合后恢复，不抢占鼠标 |
| PostMessageWithWindowPos | `256` | 中 | 可能 | 否 | 是 | 短暂移动窗口使目标位置与光标重合后恢复，不抢占鼠标 |

> [!NOTE]
>
> - 管理员权限主要取决于目标程序的权限级别，若目标程序为管理员权限，则需以管理员权限运行以保证兼容性。
> - `WithCursorPos` 系列方式会短暂移动光标到目标位置，发送完消息后会将光标移回原位置，因此会“短暂”抢占鼠标，但不会阻止用户操作。
> - `WithWindowPos` 系列方式会短暂移动窗口，使目标位置与当前光标位置重合，发送完消息后会将窗口移回原位置。不会移动光标，因此不抢占鼠标，但窗口会短暂闪烁。
> - 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](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaDef.h#L295-L325)

将下面选择的方式 **按位或** 合并为一个值提供。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 | ScreenDC`  
> - `MaaWin32ScreencapMethod_Background`：`FramePool | PrintWindow`  
>
> FramePool 和 PrintWindow 内置了伪最小化支持：当目标窗口被最小化时，会将窗口设为透明并开启点击穿透，以不激活的方式恢复窗口，从而在不打扰用户的情况下继续截图。  
> 其他截图方式在窗口最小化后无法获取有效内容，请避免窗口最小化。

## MacOS

MacOS 控制器用于在 macOS 上控制原生 macOS 应用程序。

### MacOS 前置要求

1. macOS 14.0 及以上版本
2. 需要授予以下权限：
   - **录屏权限 (Screen Recording)**：用于截图功能
   - **辅助功能权限 (Accessibility)**：用于输入控制功能

### 权限调试

如果遇到权限相关问题，可以通过以下命令重置权限：

```bash
# 重置录屏权限
tccutil reset ScreenCapture

# 重置辅助功能权限
tccutil reset Accessibility
```

> [!TIP]
>
> 重置权限后需要重新启动应用程序，并重新授予权限。

> [!TIP]
>
> MaaFramework 不负责权限申请和引导，Client需要自行实现相关功能。MaaToolkit 中提供了部分辅助函数，可以参考 [test/macos_test](https://github.com/MaaXYZ/MaaFramework/tree/main/test/macos_test)

### MacOS Screencap

> 参考 [MaaDef.h](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaDef.h#L363-L377)

选择下面的值提供。

无默认值。Client 可以选择一个作为默认值。

| 名称 | API 值 | 速度 | 兼容性 | 需权限 | 支持后台 | 说明 |
| --- | --- | --- | --- | --- | --- | --- |
| ScreenCaptureKit | `1` | 快 | 高 | 录屏权限 | 是 | 需要 macOS 14.0+ |

### MacOS Input

> 参考 [MaaDef.h](https://github.com/MaaXYZ/MaaFramework/blob/main/include/MaaFramework/MaaDef.h#L378-L392)

选择下面的值提供。

无默认值。Client 可以选择一个作为默认值。

| 名称 | API 值 | 兼容性 | 需权限 | 支持后台 | 说明 |
| --- | --- | --- | --- | --- | --- |
| GlobalEvent | `1` | 高 | 辅助功能权限 | 否 | 通过 `CGEventPost(kCGHIDEventTap)` 向全局 HID 事件流注入，由系统分发至前台窗口（会自动激活目标窗口） |
| PostToPid | `2` | 中 | 辅助功能权限 | 是 | 通过 `CGEventPostToPid` 直接发送至目标进程，无需目标窗口处于前台 |

## PlayCover (macOS)

PlayCover 控制器用于在 macOS 上控制通过 [fork版PlayCover](https://github.com/hguandl/PlayCover/releases) 运行的 iOS 应用程序。

### PlayCover 前置要求

1. 在 macOS 上安装 [fork版PlayCover](https://github.com/hguandl/PlayCover/releases)
2. 目标 iOS 应用需要在 PlayCover 中启用 MaaTools 功能

## Gamepad (Windows)

Gamepad 控制器用于在 Windows 上模拟 Xbox 360 或 DualShock 4 手柄输入，适用于需要手柄控制的游戏。

### Gamepad 前置要求

需要安装 [ViGEm Bus Driver](https://github.com/ViGEm/ViGEmBus/releases)。

### 手柄类型

| 类型 | 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 才能使用此控制器。

## WlRoots (Linux)

WlRoots 控制器用于在 Linux 上控制在专用 wlroots 合成器中运行的应用程序。

### 合成器前置要求

待控制的 wlroots 合成器必须支持以下协议：

- Wayland 核心协议
- `virtual-keyboard-unstable-v1`
- `wlr-screencopy-unstable-v1`
- `wlr-virtual-pointer-unstable-v1`

> [!NOTE]
>
> 建议启动一个嵌套合成器会话以使用该控制器。不建议控制当前桌面所使用的合成器，这可能会在任务执行过程中产生意外行为。

### 键盘输入说明

WlRoots 控制器下，使用 MaaControllerPostKey{Down,Up} 传入的按键**默认**为 evdev 扫描码，定义见 [linux/input-event-codes.h](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h)。

如需使用 Win32 Virtual-Key 键码（VK_*），在创建控制器时将 `MaaWlRootsControllerCreate` 的 `use_win32_vk_code` 参数置为 `true` 即可。开启后，`MaaControllerPostClickKey` / `MaaControllerPostKey{Down,Up}` 所接受的键码会被视为 Win32 VK 键码并在内部转换为 evdev 码。此开关在创建时一次性决定，不可运行时修改，便于从 Win32 控制器的代码中迁移按键逻辑到 WlRoots。
