<<<<<<< HEAD
用 C++ / Qt 6 实现的 Windows 11 风格 Ctrl+Alt+Delete 安全选项屏幕(Secure Attention Sequence)。 按下组合键后弹出全屏锁定层:锁定 / 切换用户 / 注销 / 更改密码 / 任务管理器, 右下角提供网络、无障碍与电源按钮,Esc 或「取消」退出。
支持 X11 与 Wayland(GNOME / KDE / Sway / Hyprland / Niri 等)。
┌────────────────────────────────────────────────────┐
│ (毛玻璃/暗色全屏遮罩) │
│ 安全选项 │
│ ┌──────────────┐ │
│ │ 锁定 │ │
│ │ 切换用户 │ ← 居中菜单列 │
│ │ 注销 │ (JSON 可配置) │
│ │ 更改密码 │ │
│ │ 任务管理器 │ │
│ └──────────────┘ │
│ [取消] [网络][无障碍][电源] │
└────────────────────────────────────────────────────┘
- 依赖软件
- 功能特性
- 一键安装 / 卸载(自动检测 DE/WM)
- 屏蔽 systemd 默认行为
- 会话适配总览
- X11 会话(零配置)
- Wayland —— 桌面环境
- Wayland —— 平铺窗口管理器教程(非 DE)
- 配置:按钮 → 命令映射
- 架构
- 常见问题
- 安全说明
SAS 本体只依赖 Qt 6(Widgets/Network/DBus)+ libxcb;下列为默认按钮动作用到的外部程序,
均带 fallback 回退链——缺少某个也没关系,程序会自动尝试下一项,或由你在 config.json 中替换。
| 功能 | 用到的软件(按尝试顺序) | 包名示例(Arch / Debian) |
|---|---|---|
| 任务管理器 | missioncenter → gnome-system-monitor → ksysguard → xfce4-taskmanager | missioncenter / mission-center |
| 更改密码 | 默认终端($TERMINAL → xdg-terminal-exec → kitty → alacritty → wezterm → foot → gnome-terminal → konsole → xfce4-terminal → xterm)+ passwd |
xdg-utils、kitty… / 同上 |
| 锁定 / 切换用户 / 注销 | loginctl(systemd) |
systemd(系统自带) |
| 注销(fallback) | qdbus6/qdbus(KDE KSMServer)→ gnome-session-quit → niri msg → swaymsg → hyprctl | 随对应桌面环境安装 |
| 电源(睡眠/关机/重启) | systemctl(systemd) |
systemd(系统自带) |
| 网络面板 | NetworkManager(nmcli,首选)或 iwd(D-Bus) |
networkmanager / iwd |
| 无障碍 | plasma-open-settings → systemsettings → gnome-control-center | 随 KDE/GNOME 安装 |
任务管理器建议安装 Mission Center:系统级实时监控,功能最接近 Windows 任务管理器。 网络面板二选一后端即可:两者都有时优先 NetworkManager(Arch 上常见组合为 NM 主控 + iwd 驱动 Wi-Fi,仍走 nmcli)。
| 特性 | 实现方式 |
|---|---|
| 全屏置顶覆盖 | Qt::FramelessWindowHint + WindowStaysOnTopHint + showFullScreen() + raise();X11 加 X11BypassWindowManagerHint;KDE 写 keepabove 窗口规则、Hyprland 加 windowrule = keepabove,确保盖住桌面与所有窗口 |
| 毛玻璃背景 | X11:截取当前屏幕 → QGraphicsBlurEffect 模糊 + 暗色遮罩;KDE/Hyprland 可用混成器原生 blur(见下文) |
| 按键拦截 | X11:QWidget::grabKeyboard() 全键盘抢占;Wayland:全屏窗口 + 混成器焦点(协议限制,见 FAQ) |
| 全局热键 | X11:xcb_grab_key 独立连接监听;Wayland:混成器快捷键转发 sas-screen --show(冷启动) |
| 应用内网络面板 | 右下角「网络」打开内置 Wi-Fi 切换面板:自动识别 NetworkManager(nmcli)或 iwd(D-Bus),列出附近网络、输密码连接、断开 |
| 退出 | Esc 或「取消」按钮 |
| 单实例 | QLocalServer / QLocalSocket IPC,重复触发由同一进程弹窗 |
| 外部命令解耦 | config/sas-screen.json 定义按钮 → 命令映射,QProcess::startDetached 执行 |
一条命令完成全部安装与绑定:编译 → 安装 → mask systemd target → 自动检测当前
桌面环境/窗口管理器并完成对应的快捷键与毛玻璃配置。不写入任何自启动项——快捷键统一
绑定 sas-screen --show 按需冷启动,登录后不会自动打开界面。
./deploy/install.sh # 普通用户:安装到 ~/.local
sudo ./deploy/install.sh # 系统级:安装到 /usr/local(用户级配置自动交给原用户执行)安装脚本自动识别以下环境并直接配置,无需再手动操作:
| 检测到 | 自动完成 |
|---|---|
| X11(任意 DE) | 无需配置 —— 运行中的实例自动 xcb_grab_key 注册全局热键 |
| GNOME | gsettings 自定义快捷键绑定 <Control><Alt>Delete |
| KDE Plasma | 安装 KWin 脚本(快捷键绑定)+ 写入 kwinrulesrc 毛玻璃 + keepabove 置顶规则 + 启用脚本 |
| Hyprland | 写入 hyprland.conf:bind 热键 + keepabove/blur 窗口规则 |
| Sway | 写入 sway/config:bindsym 热键 |
| Niri | 新建 niri/sas-screen.kdl(独立文件),并在 config.kdl 中 include:binds 热键 |
检测依据:XDG_CURRENT_DESKTOP / XDG_SESSION_TYPE → 进程名(gnome-shell、plasmashell、
Hyprland、sway、niri)→ 配置文件存在性(~/.config/{hypr,sway,niri})。配置块带
# >>> SAS Screen <<< 标记(Niri 用 KDL 格式,为 // >>> SAS Screen <<<),重复安装自动替换、卸载自动清除。脚本可重复执行(幂等)。
手动编译安装:
# 编译
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
# 运行
./build/sas-screen --help
# 手动安装(不写自启:按快捷键时 --show 冷启动)
cmake --install build --prefix ~/.local
mkdir -p ~/.local/share/sas-screen
cp config/sas-screen.json ~/.local/share/sas-screen/./deploy/uninstall.sh # 移除一切:二进制、KWin 脚本/规则、GNOME 快捷键、WM 配置块
sudo ./deploy/uninstall.sh # 若当初用 root 安装卸载脚本还会:
- 将你自定义的
~/.config/sas-screen/config.json备份为config.json.bak; - 询问是否恢复
ctrl-alt-del.target(Ctrl+Alt+Delete 重新触发重启),默认不恢复。
依赖:CMake ≥ 3.16、Qt 6(Widgets + Network)、libxcb(X11 会话需要;Wayland 仅用 Qt 时可省略)。
Linux 内核把 Ctrl+Alt+Delete 转成 SIGINT 发给 PID 1,systemd 默认响应为重启。 不屏蔽的话,即使界面弹出,松开按键也会触发重启:
sudo systemctl mask ctrl-alt-del.target
sudo systemctl daemon-reload
# 恢复:sudo systemctl unmask ctrl-alt-del.target或直接运行 sudo ./deploy/deny-systemd-cad.sh。
| 会话 | 触发方式 | 焦点抢占 | 毛玻璃 |
|---|---|---|---|
| X11 | 程序自动 xcb_grab_key(零配置) |
grabKeyboard() 全键盘 |
内置截屏模糊 |
| GNOME (Wayland) | gsettings 自定义快捷键 |
全屏窗口 | 无(深色背景) |
| KDE (Wayland/X11) | KWin 脚本或系统设置快捷键 | 全屏窗口 | KWin Blur 窗口规则 |
| Hyprland | bind 绑定 |
全屏窗口 | windowrule = blur |
| Sway | bindsym 绑定 |
全屏窗口 | 无(深色背景) |
| Niri | include 引入独立 sas-screen.kdl |
全屏窗口 | 无(深色背景) |
Wayland 无全局键抓取协议(global shortcuts 协议尚未普及),因此一律由混成器把 Ctrl+Alt+Delete 转成
sas-screen --show;程序内部已做单实例,重复触发只弹窗、不重复启动。 全屏 + 置顶:KDE 通过keepabove窗口规则、Hyprland 通过windowrule = keepabove强制盖住 桌面与所有窗口;Sway/Niri 的全屏窗口天然置顶。
X11 下无需任何配置:运行中的实例自动在 root 窗口注册 Ctrl+Alt+Delete 被动抓取,
按下即弹窗;界面上 grabKeyboard() 抢占全键盘(Alt+Tab 等 WM 快捷键也会被锁住)。
未识别 DE 时不写自启,请把 sas-screen 加进你自己的登录启动器;DE 场景下快捷键即点即开。
sas-screen # 后台运行(注册 X11 全局热键)
sas-screen --show # 手动触发一次(未运行时也会自行启动并弹窗)注意事项:
- 若桌面环境占用了 Ctrl+Alt+Delete(如 KDE 默认的注销),需先在系统设置中删除该快捷键,否则抓取失败(启动日志会提示)。
- 已 mask
ctrl-alt-del.target后,该组合键不会再有副作用。
./deploy/install.sh已自动完成以下配置。本节为手动方式,供脚本不可用或想自定义时参考。
./deploy/gnome/install-shortcut.sh脚本等价于:
gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings \
"['/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/sas-screen/']"
gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/sas-screen/ \
name 'SAS Screen'
gsettings set ...sas-screen/ command 'sas-screen --show'
gsettings set ...sas-screen/ binding '<Control><Alt>Delete'GNOME(Mutter)不支持窗口模糊,SAS 显示为深色暗化背景。
./deploy/kde/install-kwin.sh脚本做两件事:
- 安装 KWin 脚本
deploy/kde/kwin-sas-screen/到~/.local/share/kwin/scripts/(绑定 Ctrl+Alt+Delete); - 向
~/.config/kwinrulesrc写入窗口规则[SASScreenBlur],为sas-screen启用 KWin Blur —— X11 与 Wayland 下都是真正的毛玻璃。
安装后到 系统设置 → 窗口管理 → KWin 脚本 勾选并应用。
./deploy/install.sh可自动检测 Hyprland / Sway / Niri 并完成全部写入。 以下为手动教程,适用于脚本无法识别或想亲手配置的情况。
以 Hyprland / Sway / Niri 为例。两步走:
- 绑定:把 Ctrl+Alt+Delete 转发给
sas-screen --show(冷启动,无需自启常驻); - mask:确保 systemd 不响应此组合键(见上文,所有 WM 通用)。
编辑 ~/.config/hypr/hyprland.conf(或直接把 deploy/wayland/hyprland.conf.hint 合并进去):
# 绑定(不写 exec-once 自启:--show 会自行冷启动)
bind = CONTROL ALT, Delete, exec, sas-screen --show
# 可选:毛玻璃(Hyprland 原生 blur,作用于半透明窗口)
windowrule = blur, class:^(sas-screen)$
windowrule = opacity 0.92 0.92, class:^(sas-screen)$hyprctl reload 或按 Mod+Shift+R 生效。验证:按 Ctrl+Alt+Delete 应弹出全屏界面,Esc 关闭。
若按钮命令需要终端(如「更改密码」),程序自动使用用户默认终端
($TERMINAL → xdg-terminal-exec → kitty/alacritty/… → xterm 回退链)。
编辑 ~/.config/sway/config:
bindsym Control+Alt+Delete exec sas-screen --showMod+Shift+C 重载。Sway 无 blur,显示为深色背景。
Niri 的配置是 KDL 格式(~/.config/niri/config.kdl)。不要直接改主配置,
把 SAS 的配置放进独立文件,再用 include 引入:
// ~/.config/niri/config.kdl 中加入一行(相对路径基于配置目录解析):
include "sas-screen.kdl"// ~/.config/niri/sas-screen.kdl —— 独立文件内容(Niri 是 KDL 格式,注释用 //):
binds {
Ctrl+Alt+Delete { spawn "sas-screen" "--show"; }
}要点:
- Niri 配置为 KDL 格式,注释用
//(不是#),自动配置块标记也相应使用//; - Niri 键名沿用 X11 keysym 命名:
Ctrl/Control、Alt、Delete直接可写; include相对路径基于配置目录解析(与include "dms/binds.kdl"同理),install.sh自动写入相对路径;- 卸载时只需删除 include 行和
sas-screen.kdl文件,主配置零污染; - 配置重载:
Mod+Shift+R;按Mod+Shift+/可打开快捷键列表确认绑定已生效; - 全屏窗口在 Niri 中占满当前工作区并置顶;
- Niri 目前无原生模糊,SAS 显示为深色暗化背景(配合
opacity类窗口规则可微调观感)。
凡是能"全局快捷键 → 执行命令"的组合键机制都能接入,要点只有一个:
绑定 sas-screen --show(冷启动自带单实例与弹窗,无需常驻进程)。
例如 river / wayfire / labwc 等均可照此办理。
配置文件查找顺序:--config <file> → ~/.config/sas-screen/config.json
→ <安装目录>/../share/sas-screen/sas-screen.json → 内置默认值。
{
"buttons": {
"锁定": { "command": "loginctl", "args": ["lock-session"], "exitAfter": true },
"切换用户": { "command": "loginctl", "args": ["lock-session"], "exitAfter": true },
"注销": { "command": "loginctl", "args": ["terminate-session", "self"],
"fallback": [
{ "command": "qdbus6", "args": ["org.kde.ksmserver", "/KSMServer", "logout", "0", "0", "0"] },
{ "command": "gnome-session-quit", "args": ["--logout", "--no-prompt"] },
{ "command": "niri", "args": ["msg", "action", "quit"] },
{ "command": "swaymsg", "args": ["exit"] },
{ "command": "hyprctl", "args": ["dispatch", "exit"] }
], "exitAfter": true },
"更改密码": { "command": "xdg-terminal-exec", "args": ["passwd"],
"fallback": [
{ "command": "kitty", "args": ["-e", "passwd"] },
{ "command": "gnome-terminal", "args": ["--", "passwd"] },
{ "command": "konsole", "args": ["-e", "passwd"] }
], "exitAfter": true },
"任务管理器": { "command": "missioncenter", "args": [],
"fallback": [
{ "command": "gnome-system-monitor", "args": [] },
{ "command": "ksysguard", "args": [] },
{ "command": "xfce4-taskmanager", "args": [] }
], "exitAfter": true }
},
"footer": {
"network": { "command": "", "args": [],
"注释": "空命令 → 打开应用内 Wi-Fi 切换面板(自动识别 NetworkManager/iwd)" },
"accessibility": { "command": "plasma-open-settings", "args": ["accessibility"],
"fallback": [
{ "command": "systemsettings", "args": ["kcm_access"] },
{ "command": "gnome-control-center", "args": ["universal-access"] }
] }
}
}command为空 → 该按钮不显示(footer.network例外:空命令表示打开应用内网络面板);fallback:主命令不存在时按顺序尝试备用命令;exitAfter:点击后是否自动关闭 SAS 界面(默认true);- 「更改密码」未配置时自动使用用户默认终端:
$TERMINAL→xdg-terminal-exec→ kitty / alacritty / wezterm / foot / gnome-terminal / konsole / xfce4-terminal / xterm; - 电源菜单(睡眠/关机/重启)为内置动作,执行
systemctl suspend|poweroff|reboot,不可配置。
src/
├── main.cpp 入口:平台检测、单实例 IPC、装配
├── saswindow.h/.cpp 全屏 UI:毛玻璃背景、居中菜单、底部栏、Esc/取消
├── networkdialog.h/.cpp 应用内 Wi-Fi 切换面板(NetworkManager/iwd 后端自动识别)
├── commandmap.h/.cpp JSON 配置加载 + QProcess 外部命令执行(含 fallback)
└── x11grabber.h/.cpp X11 独立 xcb 连接:xcb_grab_key 监听 Ctrl+Alt+Delete
deploy/
├── install.sh 一键安装:编译+安装+DE/WM 自动检测配置
├── uninstall.sh 一键卸载:清理所有痕迹
├── deny-systemd-cad.sh mask ctrl-alt-del.target(独立脚本)
├── gnome/install-shortcut.sh gsettings 快捷键(手动方式)
├── kde/kwin-sas-screen/ KWin 脚本(main.js + metadata.desktop)
├── kde/install-kwin.sh KWin 手动安装 + 毛玻璃窗口规则
└── wayland/*.config.hint Sway / Hyprland / Niri 手动配置片段
触发链路:
X11: Ctrl+Alt+Delete ──(xcb_grab_key)──► X11Grabber::activated ─┐
├─► SasWindow::showSas
Wayland: 混成器快捷键 ──(spawn sas-screen --show)──► IPC ────────┘
模态抓取说明:X11 下用 QWidget::grabKeyboard()(在 Qt 自己的 X 连接上执行,
事件才会正常流入 Qt 事件循环);热键监听则使用独立的 xcb 连接(两个连接互不干扰)。
Q: 按 Ctrl+Alt+Delete 没反应(X11)
检查是否有其它程序占用了该组合键(如 KDE 注销快捷键);日志会输出失败原因(journalctl --user -u sas-screen 或直接运行观察 stderr)。
Q: 界面上毛玻璃不生效
- GNOME / Sway / Niri:平台本身无窗口模糊能力,属预期行为(显示为深色背景);
- KDE:确认 KWin 脚本与 Blur 特效(系统设置 → 桌面特效)已启用;
- Hyprland:确认已加
windowrule = blur且 Hyprland 未禁用 decoration blur。 Q: 「任务管理器」点了没反应
missioncenter / gnome-system-monitor / ksysguard / xfce4-taskmanager 均未安装 → 在 config/sas-screen.json 中换成你实际安装的工具,或填写你的假任务管理器命令。
Q: 「网络」点了没反应
正常情况下点「网络」会打开应用内 Wi-Fi 面板(列表、连接、断开、刷新),不依赖外部设置程序。 若面板提示"未检测到网络后端",说明系统里既没有 NetworkManager 也没有 iwd,请安装其一后重启面板。 纯有线用户可用:面板始终可用,断开/连接仅针对 Wi-Fi。
Q: 「注销」点了没反应
默认链依次尝试:loginctl terminate-session self → KDE ksmserver logout → GNOME gnome-session-quit
→ niri msg action quit → swaymsg exit → hyprctl dispatch exit。
若仍无效,多半是会话管理器特殊(或你在容器/嵌套会话里),可在 config.json 的「注销」中改成你 DE 的退出命令。
Q: 「无障碍」点了没反应
plasma-open-settings / systemsettings kcm_access / gnome-control-center universal-access 均不可用时,
在 config/sas-screen.json 的 footer.accessibility 中换成你 DE 的无障碍设置入口。
Q: 关机会弹 Polkit 授权?
systemctl poweroff 走 Polkit,这是系统策略而非程序行为;可在 config.json 中把电源动作改为你偏好的命令。
Q: Wayland 下无法真正"锁住"别的窗口 Wayland 协议不允许应用抓取全局键盘/指针(只有混成器可以)。本程序靠全屏窗口独占,已满足绝大多数场景;这是 Wayland 的架构性限制,非 bug。
本程序是界面级还原,不是真正的 Secure Attention Sequence:
- 真正的 Windows SAS 由内核(Winlogon)截获,任何用户态程序都无法伪造;
- 本程序的 Ctrl+Alt+Delete 监听运行于用户态,恶意进程理论上可模仿;
- 锁定/关机等动作依赖
loginctl/systemctl与 Polkit 授权,请勿把它当作安全边界使用。
e79c2c9 (首次提交)