起因是 /t/1044916 这个帖子,我原本认为这个方法会在开发者群体里很普遍,结果问了一圈才发现几乎没人用。我在 B 站也尝试搜索了一下,没有看到类似的用法,所以就有了这个帖子。
这个方案解决了什么问题
外出环境需要扩展副屏,用于临时多屏提高效率或者展示
老旧平板废物利用
这个方案的优点在哪里
只依赖开源软件,免费可信。无需采集卡、或者商业软件
无需物理连线,任何手机、平板都可以作为副屏
可扩展的屏幕数量没有上限,不需要 HDMI 欺骗头
可以自定义输出的分辨率,主动匹配显示设备( HDMI 欺骗头也可以通过重写 EDID 来实现,但不如软件方便)
支持低功耗(远程桌面)和低延迟(串流)模式,在移动办公场景,远程桌面模式几乎不会带来功耗增加
支持副屏单独操作副屏的窗口,不影响主机操作( multi-seat 或者多焦点,这个功能仅限 Linux 主机)
实现原理
原理简单说分两部分,一部分是传统的 vnc/rdp/sunshine 软件,前两者是远程桌面模式,后者是串流模式。
由于单纯的远程桌面、串流都需要先有一个桌面,属于镜像模式,对于“扩展屏”的场景来说没有帮助。所以第二个部分就是如何增加一个虚拟的桌面。
之前的方法是 HDMI 欺骗头,这样就只能输出一个副屏。软件的方法如下:
Windows 使用 Virtual-Display-Driver 也有其他的实现可以用
Linux 目前有 X11/wayland 两个显示框架,X11 有 xvfb/xrdp 可以用,我很久都没用过 X11 了,所以这两个仅供参考,但是 X11 的支持是没什么问题的。
Wayland 的话 KDE/KWin 是不行的。Gnome/Mutter 在 42 版本为了自家 rdp 应用增加了一个功能,可以创建一个虚拟桌面,这个 rdp 应用可以把这个虚拟显示器作为后端。wlroots 的实现 sway/hyprland 都支持直接创建。
macOS 我不知道……我主动远离苹果生态很久了。欢迎补充。
剩下的事情就顺理成章了,让 vnc/rdp/sunshine 跑在这个虚拟显示器就可以。
这样就可以根据显示设备的分辨率,创建一个虚拟显示器。平板手机连接对应的 vnc/rdp/moonlight 即可点对点显示。
实现原理续
远程桌面模式需要实际测试一下 vnc/rdp/moonlight 客户端。
以 Android 平板上的 vnc 客户端为例,如果需要在平板上滑动屏幕,实现显示区域里的浏览器窗口滚动,就需要这个 vnc 客户端将平板的输入映射为鼠标滚轮(或者手势)传递给 vnc 服务器端。不是所有的客户端都实现了类似的功能。
Sway wm 环境还可以使用 seat 的功能对输入进行分组。vnc 服务器端会创建虚拟的鼠标、键盘或者触摸板输入设备,当客户端有输入传入时,相应指令就会通过虚拟设备发送给系统。
这样能够实现实现:主机和触摸屏有两组输入焦点,副屏由于物理限制只能使用副屏桌面的应用。这对于演示场景非常有用,展示应用在副屏,客户还可以通过触屏实际体验。而主屏幕任何操作都不会受影响。
额外补充
如果需要非常低的延迟,优选 sunshine/moonlight 的串流模式。由于现在的 cpu 普遍有硬件编码器,而平板作为播放器又都有硬件解码器,这个功能对于平板几乎没有硬件限制,十年前能硬解 h264 的即可,稍微新一点的硬件都可以利用上 hevc/av1 方案。
实测下来,1080p60~10Mbps 大概硬件编码器功耗在 0.8W 左右,虽然比较低,但是会导致 cpu 一直后台处理网络功能,无法进入低功耗状态,所以只推荐固定场景有外接电源时使用。
相对来说,vnc/rdp 模式更适合静态展示或者终端应用,这一类都是基于画面变化传输数据,对于功耗续航的影响很小,开手机热点即可快速建立连接。
外出组网,方便的是手机开热点,然后笔记本和平板都连接热点。如果是笔记本开热点需要手动设置,一个频段上网,另一个频段共享。反过来平板开热点,平板有可能访问不到在热点子网里的笔记本。
使用指南
这里就以我用的 sway/wayvnc 做个说明,其他的根据自己情况调整即可。需要做的就是两件事,创建虚拟输出,然后把输出投屏出去。图我就不放了,大家脑部一下效果就好。
# 创建虚拟输出
swaymsg create_output
# 由于目前 wlroots 实现,这个输出的名字默认为 HEADLESS-1 ,继续创建则为 HEADLESS-2 以此类推
# 可以在 sway config 中预定义其输出参数,也可以通过 IPC 手动调整
# 在 (2560,0) 位置创建 1920x1200 的虚拟显示器
swaymsg output HEADLESS-1 mode 1920x1200 pos 2560,0
# 启动 vnc 服务端并将 HEADLESS-1 作为显示后端,设定监听入口
wayvnc --output=HEADLESS-1 0.0.0.0 5900
# 如果需要单独输入设备为单独 seat
# 目前 wayvnc 不支持直接创建 seat ,所以需要先创建 seat1 来占位,系统默认的是 seat0
swaymsg seat seat1 attach PLACEHOLDER
# 将 wayvnc 输入设备绑定到 seat1
wayvnc --output=HEADLESS-1 --seat=seat1 0.0.0.0 5900
# 临时切断副屏输出
swaymsg output HEADLESS-1 toggle
# 反正用 sway 的基本都有自己的自动化逻辑,这一整套可以完全自定义
1
swordsmile 95 天前
如果是 Hyprland ,如何创建虚拟 seat 呢
|
![]() |
2
kuanat OP @swordsmile #1
Hyprland 目前还不支持 multi-seat 功能 https://github.com/hyprwm/Hyprland/issues/1731 这也是我一直主用 sway 的原因。其他方面 hyprland 易用性好太多了,不得已我还给 sway 写了个简陋的 master stack 布局管理器…… 另外还有些 layer-shell 协议的应用(悬浮显示状态、通知和关机菜单这一类)也是硬编码了 seat0 的,有可能会导致显示位置或者输入焦点异常。对我影响比较大的是 tofi (一个 wofi 的改版)会有输入焦点问题。 |