8.游戏手柄模拟
在 PC 上玩 Android 游戏,触屏操作终究不如实体手柄来得顺手。scrcpy 很早就意识到了这一点,提供了完整的游戏手柄模拟能力。这并非简单的按键映射,而是直接在 Android 系统底层模拟出一个真实的 HID 游戏手柄设备,让游戏完全感知不到差异。
物理手柄模拟原理
scrcpy 的游戏手柄模拟核心思路,与键盘鼠标的物理模拟一脉相承。它不会在应用层做简单的按键转发,而是通过 Linux 内核的 UHID 模块或 USB 的 AOAv2 协议,在 Android 设备上创建一个虚拟的物理游戏手柄设备。这个虚拟手柄在系统看来,与通过蓝牙或 USB 直连的真实手柄没有任何区别。
这种设计的优势显而易见。首先,兼容性极佳,几乎所有支持手柄的游戏都能直接使用,无需单独配置按键映射。其次,延迟极低,因为输入事件走的是系统底层通道,绕过了 Android 的输入方法框架。最后,支持完整的游戏手柄特性,包括摇杆、扳机键、方向键、动作键等所有标准输入。
默认情况下,游戏手柄模拟是关闭的。scrcpy 不会自动劫持连接在 PC 上的手柄,需要显式启用。这种保守设计避免了与 PC 本地游戏的冲突,把选择权交给了用户。
与键盘鼠标模拟的异同
游戏手柄模拟在技术上与键盘鼠标的 UHID/AOA 模式同源,都是利用 HID 协议创建虚拟设备。但手柄有其特殊性:它是一个独立的输入设备类别,拥有更复杂的轴输入(摇杆、扳机)和更多的按键。
在实现层面,scrcpy 为每个连接到 PC 的物理手柄,在 Android 设备上创建一个对应的虚拟手柄。这意味着如果 PC 上插了两个手柄,Android 上也会识别出两个手柄,非常适合本地多人游戏场景。
需要注意的是,手柄模拟与视频流、音频流是独立的。可以只开启手柄模拟而不进行屏幕镜像,这在某些场景下很有用,比如配合实体显示器玩游戏,或者纯粹作为手柄转发器使用。
UHID 与 AOA 模式配置
scrcpy 提供了两种物理手柄模拟模式:UHID 和 AOA。两者在功能上相似,但工作层级和适用场景有显著差异。
UHID 模式配置
UHID(User-space HID)模式利用 Android 内核的 UHID 模块,在用户空间创建虚拟 HID 设备。这是推荐的首选模式,支持无线连接,兼容性也更好。
启用 UHID 游戏手柄非常简单:
scrcpy --gamepad=uhid
更简洁的短参数形式:
scrcpy -G
这条命令会启动完整的 scrcpy 会话(包括视频、音频),同时启用游戏手柄模拟。连接在 PC 上的手柄会自动被识别并转发到 Android 设备。
如果只想用手柄控制而不需要屏幕镜像,可以关闭音视频:
scrcpy --no-video --no-audio --gamepad=uhid
UHID 模式的优势很明显:它通过 adb 隧道工作,因此支持 TCP/IP 无线连接。只要设备能通过 adb connect 无线连接,手柄模拟就能正常工作。这让我们在沙发上用无线手柄玩 Android 游戏成为可能。
不过 UHID 也有局限性。旧版 Android 系统可能存在权限问题,导致无法创建虚拟设备。此外,它依赖 adb 连接,如果 adb 服务不稳定,手柄输入也会受影响。
AOA 模式配置
AOA(Android Open Accessory)模式工作在 USB 协议层,不依赖 adb。它通过 AOAv2 协议的 HID 支持功能,直接将 PC 模拟为 USB 配件,在 Android 上创建虚拟手柄。
启用 AOA 游戏手柄:
scrcpy --gamepad=aoa
AOA 模式的最大特点是独立性。它不需要开启 USB 调试,甚至不需要 adb 服务运行。只要设备通过 USB 线连接,就能用手柄控制。这在某些受限环境下很有价值。
但 AOA 的限制也更严格:仅支持 USB 连接,无法无线使用。更麻烦的是,在 Windows 系统上,AOA 模式可能与 adb 冲突。由于 Windows 不允许多个进程同时打开同一个 USB 设备,如果 adb 守护进程正在管理设备,AOA 模式可能无法启动。这种情况下,只能使用 OTG 模式,或者先停止 adb 服务。
另一个需要注意的点是多手柄支持。文档明确指出,AOA 模式下 Android 会将多个物理手柄识别为一个行为异常的设备。如果需要连接多个手柄,必须使用 UHID 模式。
模式对比与选择
简单总结两者的差异:
- 连接方式:UHID 支持 USB 和无线;AOA 仅支持 USB
- 依赖关系:UHID 需要 adb;AOA 不需要 adb,不依赖 USB 调试
- 平台兼容性:UHID 在所有平台表现一致;AOA 在 Windows 上可能有冲突
- 多设备支持:UHID 完美支持多个手柄;AOA 多手柄支持有问题
- 系统要求:UHID 需要较新的 Android 版本;AOA 对 Android 版本要求较低
选择建议很明确:优先使用 UHID 模式。只有在无线连接不可用,或者需要在没有 USB 调试的环境下使用时,才考虑 AOA 模式。对于绝大多数场景,UHID 的灵活性和稳定性都更胜一筹。
手柄映射与校准
与键盘鼠标不同,游戏手柄的映射相对标准化。scrcpy 遵循标准的 Linux 游戏手柄按钮和轴编号,这意味着大多数手柄无需额外配置就能正常工作。
自动识别与映射
当启用 --gamepad=uhid 或 --gamepad=aoa 后,scrcpy 会监控 PC 上的输入设备。一旦检测到手柄连接,立即在 Android 上创建对应的虚拟设备。手柄断开时,虚拟设备也会自动移除。
映射关系是自动建立的:
- 左摇杆 → 标准 X/Y 轴
- 右摇杆 → 标准 Z/Rz 轴
- 扳机键 → L2/R2 轴
- 方向键 → 标准方向键按钮
- 动作键 → A/B/X/Y 或对应按钮
- 功能键 → Start/Select/Mode 等
这种映射基于 Linux 的 input 事件标准,因此 Xbox、PlayStation、Switch Pro 等主流手柄都能正确识别。对于非常规手柄,可能需要通过 evtest 等工具查看具体的轴和按钮编号。
校准与配置
虽然 scrcpy 本身不提供手柄校准功能,但 Android 系统内置了完整的校准工具。如果发现在游戏中摇杆有漂移,或者扳机键不灵敏,可以在 Android 设置中进行校准。
对于 UHID 模式,可以通过快捷键快速打开物理输入设备的设置页面:
# 先启动带手柄支持的 scrcpy
scrcpy --gamepad=uhid
# 然后按 MOD+k 打开键盘设置页面
# 手柄设置通常在同一位置
或者手动进入:设置 → 系统 → 语言和输入法 → 物理键盘。在这里,Android 会列出所有物理输入设备,包括通过 scrcpy 创建的虚拟手柄。虽然界面写的是"键盘",但手柄的配置选项也在其中。
在设置页面,可以:
- 查看手柄连接状态
- 测试按键和轴输入
- 禁用屏幕键盘(避免游戏时弹出虚拟按键)
- 配置按键重复延迟
多手柄支持细节
UHID 模式对多手柄的支持很完善。每个手柄在 Android 上都是独立的输入设备,游戏可以正确区分玩家 1、玩家 2 等。
但需要注意连接顺序。scrcpy 按照手柄在 PC 上的检测顺序创建虚拟设备。如果断开重连,设备编号可能会变化。对于需要固定玩家顺序的游戏,最好在启动游戏前就连接好所有手柄,并且不要中途插拔。
AOA 模式的多手柄支持存在已知问题。文档明确警告,Android 会将多个手柄识别为一个异常设备。这意味着在 AOA 模式下,基本上只能使用单个手柄。如果有本地多人游戏需求,必须选择 UHID 模式。
游戏场景最佳实践
理论终究要落实到实践。在不同类型的游戏中,手柄模拟的配置和使用技巧也有所不同。
动作与射击游戏
对于《原神》《崩坏》这类动作游戏,手柄的摇杆和动作键是核心。建议配置:
scrcpy --gamepad=uhid --max-fps=60 --video-codec=h264
这里除了启用手柄,还限制了帧率为 60fps,并指定了兼容性更好的 h264 编码。动作游戏对延迟敏感,h264 虽然画质稍逊,但编码延迟通常比 h265 低。
如果网络环境好,可以进一步降低视频延迟:
scrcpy --gamepad=uhid --display-buffer=10 --v4l2-buffer=10
减少缓冲区会降低延迟,但可能增加画面卡顿的风险。需要在稳定性和延迟之间权衡。
对于射击游戏,摇杆的精度至关重要。如果发现瞄准时有卡顿,可以检查手柄的轮询率。部分高端手柄支持 1000Hz 轮询,能显著减少输入延迟。这需要在 PC 端通过手柄配置软件设置,scrcpy 会原样转发高频输入。
竞速与模拟游戏
《狂野飙车》《真实赛车》这类游戏重度依赖扳机键的线性输入。scrcpy 完整支持扳机键的模拟量,可以实现精细的油门和刹车控制。
竞速游戏通常需要长时间连续游戏,建议优化功耗:
scrcpy --gamepad=uhid --turn-screen-off --stay-awake
--turn-screen-off 会关闭设备屏幕,但游戏仍在后台运行。配合 --stay-awake 防止设备休眠,既能省电又能保护屏幕。
如果游戏支持 120fps 高刷模式,可以解锁帧率限制:
scrcpy --gamepad=uhid --max-fps=120 --video-codec=h265
高帧率对视频编码要求更高,h265 在相同码率下能提供更好的画质,适合追求视觉体验的竞速游戏。
格斗与平台游戏
格斗游戏对按键的精确度要求极高,连招输入不能有任何延迟或丢失。这类游戏建议:
scrcpy --gamepad=uhid --no-key-repeat
虽然 --no-key-repeat 主要是针对键盘的,但在某些场景下也能避免手柄按键的重复触发。更重要的是,它表明了一种优化思路:减少不必要的输入事件,确保每个按键都被精确处理。
对于需要快速连打的场景,手柄的按键重复率也很重要。部分手柄支持在 PC 端配置按键重复延迟,调整到最短可以更容易实现高速连打。
纯手柄控制场景
有时候,我们可能只想用手柄控制设备,而不需要屏幕镜像。比如设备连接了实体显示器,或者纯粹作为手柄转发器使用。
关闭视频和音频,只保留手柄控制:
scrcpy --no-video --no-audio --gamepad=uhid
这个模式下,scrcpy 的窗口不会弹出,但进程会在后台运行,持续转发手柄输入。可以通过 ps 或任务管理器查看进程状态。
如果需要同时控制多个设备,可以为每个设备启动独立的 scrcpy 进程,分别指定不同的设备和手柄:
# 设备 1
scrcpy --gamepad=uhid -s device1_serial &
# 设备 2
scrcpy --gamepad=uhid -s device2_serial &
每个进程独立管理自己的手柄映射,互不干扰。
OTG 模式下的手柄使用
OTG 模式是 AOA 手柄的特殊应用场景。它完全绕过 adb,实现真正的"即插即用":
scrcpy --otg --gamepad=aoa
或者使用短参数:
scrcpy --otg -G
OTG 模式的特点是:
- 不需要开启 USB 调试
- 不需要 adb 服务
- 只支持 USB 连接
- 自动启用 AOA 键盘和鼠标(如果未禁用)
这在一些受限环境下很有用,比如公司的测试机不允许开启调试。但如前所述,OTG 模式在 Windows 上可能与 adb 冲突。如果设备已经通过 adb 连接,OTG 模式可能无法启动。
解决方法是先断开 adb 连接:
adb disconnect
scrcpy --otg -G
或者使用不同的 USB 端口,避免设备被 adb 守护进程占用。
性能调优与故障排查
手柄模拟本身消耗的资源很少,但配合视频流时,整体性能优化仍然重要。
如果发现手柄输入延迟高,首先检查网络环境(无线连接时)。可以尝试:
# 降低视频质量,优先保证输入响应
scrcpy --gamepad=uhid -b 2M --max-fps=30
降低码率和帧率能显著减少网络带宽占用,让手柄输入数据包更快到达。
如果手柄完全无响应,检查以下几点:
- 确认手柄在 PC 上正常工作(用系统自带的游戏控制器设置测试)
- 检查 scrcpy 启动日志,看是否有 UHID 或 AOA 相关的错误
- 确认游戏支持手柄(部分游戏只支持触屏)
- 尝试重新插拔手柄或重启 scrcpy
对于 UHID 模式,权限问题是最常见的故障原因。如果日志中出现 "Permission denied" 错误,可能需要检查 Android 版本的兼容性,或者尝试 AOA 模式作为替代。
与键盘鼠标模拟的配合
游戏手柄模拟可以与键盘鼠标模拟同时启用,实现更复杂的控制方案。比如,用手柄控制角色移动,用鼠标控制视角:
scrcpy --gamepad=uhid --mouse=uhid
在这种混合模式下,需要注意输入焦点的问题。UHID 鼠标会捕获 PC 鼠标,使其只在 Android 设备上显示。可以通过 MOD 键(默认 Alt 或 Super)切换鼠标捕获状态,临时将鼠标控制权交还给 PC。
键盘模拟同样可以与手柄共存:
scrcpy --gamepad=uhid --keyboard=uhid
这在需要文字输入的场景下很有用,比如在游戏中聊天。UHID 键盘支持完整的字符集和输入法,比 SDK 键盘模式体验更好。
不过,同时启用多种输入模式会增加系统负担。在性能较弱的设备上,如果发现卡顿,可以优先保证手柄的流畅度,因为游戏对手柄的响应要求最高。
scrcpy 的游戏手柄模拟功能,本质上是为 Android 游戏在 PC 上的体验补齐了最后一块短板。它不只是简单的按键转发,而是真正在系统层面创建了虚拟设备,让游戏无法分辨真伪。配合灵活的配置选项和多种工作模式,无论是单人游戏还是本地多人对战,都能找到合适的方案。下一章,我们将探讨如何管理设备状态,让 scrcpy 在自动化和长时间运行场景中更加可靠。