diff --git a/README.md b/README.md
index 63a4f4e..a00b972 100644
--- a/README.md
+++ b/README.md
@@ -1,159 +1,126 @@
-# 小米 Raphael 设备 Linux 系统镜像构建项目
+
-本项目为小米 Raphael(Redmi K20 Pro)专属 Linux 镜像构建项目,提供完整的 Debian / Ubuntu 系统镜像构建脚本与 GitHub Actions 自动化工作流,支持多内核、多桌面、服务器版,开箱即用,适配性完善。
+#

-## 📌 项目概述
+# 📱 小米 Raphael Linux 镜像构建项目
-项目集成全套自动化构建工具链,支持内核编译、系统镜像打包,覆盖桌面端与服务器端系统,所有镜像均预装适配设备的专属驱动、固件及常用工具,无需额外配置即可正常使用。
+### Redmi K20 Pro · 一键构建 Debian / Ubuntu 系统镜像
-支持构建系统类型:
+[](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/actions)
+[](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/releases)
+[](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/stargazers)
-- **Debian 系列**:GNOME 桌面版、Phosh 移动桌面版、Server 无图形服务器版
+---
-- **Ubuntu 系列**:GNOME 桌面版、Phosh 移动桌面版、Server 无图形服务器版
+
-- **定制内核**:编译适配设备 Linux 内核
+## ✨ 项目简介
-## ✅ 设备适配状态
+本项目为 **小米 Raphael(Redmi K20 Pro)** 专属 Linux 镜像构建方案,提供完整的 Debian / Ubuntu 系统镜像构建脚本与 GitHub Actions 自动化工作流。支持多内核版本、多桌面环境,开箱即用。
-当前设备硬件适配完整,主流功能全部可用:
+## 📋 支持系统类型
-- 网络:2.4G/5G 双频 Wi-Fi、USB NCM 网络
+| 系统标识 | 桌面环境 | 发行版 | 镜像大小 |
+|:---:|:---:|:---:|:---:|
+| `debian-server` | 无(纯命令行) | Debian trixie | 3G |
+| `debian-gnome` | GNOME | Debian trixie | 6G |
+| `debian-phosh` | Phosh 移动端桌面 | Debian trixie | 6G |
+| `ubuntu-server` | 无(纯命令行) | Ubuntu resolute | 3G |
+| `ubuntu-gnome` | GNOME | Ubuntu resolute | 6G |
+| `ubuntu-phosh` | Phosh 移动端桌面 | Ubuntu resolute | 6G |
-- 外设:蓝牙(文件传输/音频输出)、USB SSH/OTG 功能、触摸屏、手电筒(支持亮度调节)
+## 🖥️ 设备硬件适配
-- 基础硬件:屏幕显示、电池检测、实时时钟、GPU 渲染、FDE 加密、音频(耳机/扬声器输出)
-
-## 📊 版本支持矩阵
-
-### 系统类型对照表
-
-|系统标识|桌面环境|基础发行版|
-|---|---|---|
-|debian-server|无(纯命令行)|Debian|
-|debian-gnome|GNOME|Debian|
-|debian-phosh|Phosh 移动端桌面|Debian|
-|ubuntu-server|无(纯命令行)|Ubuntu|
-|ubuntu-gnome|GNOME|Ubuntu|
-|ubuntu-phosh|Phosh 移动端桌面|Ubuntu|
-
-### 系统与内核版本
-
-- **Debian 版本**:trixie(默认最新)
-
-- **Ubuntu 版本**:resolute(默认最新)
-
-- **内核版本**:6.18、7.0(双版本可选)
-
-### Phosh 桌面变体
-
-- `phosh-core`:基础 Phosh 环境
-
-- `phosh-full`:完整的 Phosh 环境
-
-- `phosh-phone`:手机优化的 Phosh 环境
+| 分类 | 支持项目 | 状态 |
+|:---:|:---|:---:|
+| 🌐 **网络** | 2.4G / 5G 双频 Wi-Fi | ✅ |
+| 📡 **蓝牙** | 文件传输 · 音频输出 | ✅ |
+| 📶 **蜂窝** | 网络支持 | ❌ |
+| 🔌 **USB** | NCM 网络共享 · OTG 功能 | ✅ |
+| 🖥️ **显示** | 屏幕输出 · GPU 渲染 | ✅ |
+| 🔊 **音频** | 扬声器 · 耳机输出 | ✅ |
+| 👆 **输入** | 触摸屏 · 闪光灯(手电筒) | ✅ |
+| 🔋 **系统** | 电池检测 · 实时时钟 · FDE 加密 | ✅ |
## 🚀 快速上手
### 方式一:下载预构建镜像
-项目持续自动构建最新镜像,可直接前往 [Releases](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/releases) 页面下载,无需本地编译。
+前往 [Releases](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/releases) 页面下载最新镜像,无需本地编译。
-> **⚠️ 大文件提示**:`ubuntu-gnome-6.18` / `ubuntu-gnome-7.0` 镜像体积超过 2GB,未上传至 Releases,需前往项目 Artifacts 下载。
->
->
+> ⚠️ `ubuntu-gnome` 镜像体积超过 2GB,请前往项目 [Actions → Artifacts](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/actions) 下载。
### 方式二:GitHub Actions 自定义构建(推荐)
-1. Fork 本仓库至个人 GitHub 账号
-
-2. 进入仓库 **Actions** 页面,选择「构建系统镜像」工作流
-
-3. 点击 **Run workflow**,自定义构建参数:
-
+1. **Fork** 本仓库至个人 GitHub 账号
+2. 进入 **Actions** 页面 → 选择「构建系统镜像」工作流
+3. 点击 **Run workflow**,自定义参数:
- - **构建模式**:`parallel`并行构建全部镜像(默认) / `single` 单独构建指定镜像
+| 参数 | 说明 | 默认值 |
+|:---:|:---|:---:|
+| 构建模式 | `parallel` 并行构建 / `single` 单独构建 | `parallel` |
+| 系统类型 | 支持逗号分隔,留空则全量构建 | 全部 |
+| 内核版本 | `6.18` 或 `7.0` | `7.0` |
+| 构建工具 | `mmdebstrap` / `debootstrap` | `mmdebstrap` |
+| Phosh 变体 | 仅 Phosh 镜像生效 | `phosh-core` |
- - **系统类型**:支持多类型逗号分隔,默认全量构建
+4. 等待构建完成,镜像自动发布至 Releases
- - **内核版本**:支持 `7.0`(默认7.0可选6.18)
+## 📦 镜像特性
- - **构建工具**:`mmdebstrap`(默认) / `debootstrap`
-
- - **Phosh 变体**:仅 Phosh 桌面镜像生效,默认`phosh-core`
-
- - **系统版本**:默认 Debian: trixie、Ubuntu: resolute
-
-4. 等待工作流执行完成,镜像自动打包发布至仓库 Releases
-
-## 📦 镜像通用特性
-
-### 全版本通用
-
-- 默认配置**清华软件源**
-
-- 预装简体中文语言包、中国标准时区,开箱汉化
+### 🌐 全版本通用
+- 默认配置 **清华软件源**
+- 预装简体中文语言包 + 中国标准时区,开箱汉化
- 支持 USB NCM 网络共享,电脑直连设备 SSH
-
- 内置 SSH 服务,支持 root / 普通用户远程登录
+- 支持 **一键内核更新脚本**,在线升级定制内核
-- 支持**一键内核更新脚本**,可在线升级定制内核
-
-- 默认账号密码:
-
+| 账户 | 用户名 | 密码 |
+|:---:|:---:|:---:|
+| 普通用户 | `user` | `1234` |
+| 超级用户 | `root` | `1234` |
- - 普通用户:`user` / `1234`
+> 📌 USB NCM 连接时,设备 IP:`172.16.42.1`,SSH 连接:`ssh user@172.16.42.1`
- - 超级用户:`root` / `1234`
-
-- 设备默认 IP:`172.16.42.1`,SSH 连接命令:`ssh user@172.16.42.1`
-
-### 桌面版专属特性
+### 🎨 桌面版专属
- GNOME / Phosh 双桌面环境可选,适配桌面、移动两种使用场景
-- 已知问题:**GNOME 桌面电源键无法息屏**,后续版本持续修复
-
-### 服务器版专属特性
+### 🖥️ 服务器版专属
- 内置网络管理器,支持有线、Wi-Fi、USB 多种联网方式
-
- 开机 15 秒自动熄屏,降低设备功耗
+- 自定义快捷命令:`leijun` 关闭屏幕 · `jinfan` 点亮屏幕
-- 自定义快捷命令:`leijun` 关闭屏幕、`jinfan` 点亮屏幕
-
-## ⬆️ 内核更新教程(只做内核调试用,非必要无需更新)
+## ⬆️ 内核更新
-项目提供一键内核升级脚本,建议**root 权限**执行,快速更新设备定制内核:
+
+⚠️ 仅做内核调试用,非必要无需更新
-官方原始链接:
-
-```Plain Text
-sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/GengWei1997/kernel-deb/refs/heads/main/Update-kernel.sh)"
-```
-
-国内加速链接:
-
-```Plain Text
-sudo bash -c "$(curl -fsSL https://ghfast.top/https://raw.githubusercontent.com/GengWei1997/kernel-deb/refs/heads/main/ghproxy-Update-kernel.sh)"
-```
+建议 **root 权限** 执行,完成后重启设备即可生效。
-脚本执行完成后,重启设备即可生效新内核。
+| 链接 | 命令 |
+|:---:|:---|
+| 🌏 国内加速 | `sudo bash -c "$(curl -fsSL https://ghfast.top/https://raw.githubusercontent.com/GengWei1997/kernel-deb/refs/heads/main/ghproxy-Update-kernel.sh)"` |
+| 🌐 原始链接 | `sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/GengWei1997/kernel-deb/refs/heads/main/Update-kernel.sh)"` |
-## 🔧 设备安装教程
+
-### 前置准备
+## 🔧 安装教程
-1. 设备已完成 **Bootloader 解锁**
+### 前置条件
-2. 在电脑上安装 `adb`、`fastboot` 刷机工具,并配置环境变量
-
-3. 解压下载的 `.7z` 镜像压缩包,获取 `rootfs.img`、`xiaomi-k20pro-boot.img` 下载[u-boot.img](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/releases/tag/v1.0.0)(选择最近日期版本)
+- ✅ 设备已完成 **Bootloader 解锁**
+- ✅ 电脑已安装 `adb` / `fastboot` 工具
+- ✅ 下载镜像压缩包,解压获取:
+ - `rootfs.img` — 系统镜像
+ - `xiaomi-k20pro-boot.img` — 内核镜像
+ - [u-boot.img](https://github.com/GengWei1997/linux-xiaomi-raphael-uboot/releases/tag/v1.0.0) — U-Boot 引导
### 刷机命令
-```Plain Text
+```bash
# 1. 进入 Fastboot 模式
adb reboot bootloader
@@ -163,56 +130,110 @@ fastboot erase boot
fastboot erase cache
fastboot erase userdata
-# 3. 刷入 boot 镜像
+# 3. 刷入镜像
fastboot flash cache xiaomi-k20pro-boot.img
fastboot flash boot u-boot.img
-
-# 4. 刷入系统镜像(需要先解压 rootfs.7z)
fastboot flash userdata rootfs.img
-# 5. 重启设备
+# 4. 重启设备
fastboot reboot
```
-## ❓ 常见问题 FAQ
-
-- 什么破玩意儿,开机就卡死了???(请拔掉sim卡)
-
-- **Windows 无法连接设备 CDC NCM 驱动**:参考解决方案视频[BV1tW4y1A79V](https://www.bilibili.com/video/BV1tW4y1A79V/)
-
-- **Server 版如何联网**:
-
-
- 1. OTG 外接网线,系统自动识别联网
+## ❓ 常见问题
- 2. OTG 外接键盘,终端输入 `nmtui` 可视化连接 Wi-Fi
+| 问题 | 解决方案 |
+|:---|:---|
+| 蜂窝网络支持情况 | 联通 / 电信已支持,移动正在修复中 *[@GavinLiuOnline](https://github.com/GavinLiuOnline)* |
+| Windows 无法连接设备 | 参考 [NCM 驱动教程](https://www.bilibili.com/video/BV1tW4y1A79V/) |
+| Server 版如何联网 | OTG 外接网线自动联网 · OTG 外接键盘输入 `nmtui` 连接 Wi-Fi |
- 3. USB 连接电脑,安装 NCM 驱动后,通过 `nmtui` 配置网络
+---
## 🙏 致谢
-本项目基于众多开源项目与开发者成果开发,排名不分先后,特此致谢:
-
-- Linux 内核官方开发团队、Debian / Ubuntu 开源社区、Phosh 桌面开发团队
-
-- [@degdag](https://github.com/degdag)
-
-- [@dabao1955](https://github.com/dabao1955)
-
-- [@qaz6750](https://github.com/qaz6750)
-
-- [@GavinLiuOnline](https://github.com/GavinLiuOnline)
-
-- [@umeiko](https://github.com/umeiko)
-
-- [@yuweiyuan8](https://github.com/yuweiyuan8)
-
-- [@璀璨梦星](https://github.com/ccmx200)
-
-- [@map220v](https://github.com/map220v)
-
-- [@Pc1598](https://github.com/Pc1598)
-
-- [Aospa\-raphael\-unofficial/linux](https://github.com/Aospa-raphael-unofficial/linux)、[sm8150\-mainline/linux](https://gitlab.postmarketos.org/soc/qualcomm-sm8150/linux):内核源码支持
-
-- 所有开源贡献者与项目使用者
+感谢以下开源项目与开发者的支持(排名不分先后):
+
+
+
+
+ Linux 内核官方开发团队 · Debian / Ubuntu 开源社区 · Phosh 桌面开发团队 · 以及所有开源贡献者
+
+
+---
+
+
+
+**如果这个项目对你有帮助,请给一个 ⭐ Star 支持一下!**
+
+
diff --git a/build.sh b/build.sh
index 8849f70..e5b0e96 100644
--- a/build.sh
+++ b/build.sh
@@ -104,10 +104,11 @@ echo "[$(date +'%Y-%m-%d %H:%M:%S')] ==========================================
"$SCRIPT_DIR/scripts/11-config-fstab.sh"
"$SCRIPT_DIR/scripts/12-create-users.sh"
"$SCRIPT_DIR/scripts/13-config-power.sh"
-"$SCRIPT_DIR/scripts/14-config-zram.sh"
-"$SCRIPT_DIR/scripts/15-config-audio.sh"
-"$SCRIPT_DIR/scripts/16-cleanup.sh"
-"$SCRIPT_DIR/scripts/17-finalize.sh"
+"$SCRIPT_DIR/scripts/14-config-power-key.sh"
+"$SCRIPT_DIR/scripts/15-config-zram.sh"
+"$SCRIPT_DIR/scripts/16-config-audio.sh"
+"$SCRIPT_DIR/scripts/17-cleanup.sh"
+"$SCRIPT_DIR/scripts/18-finalize.sh"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] ========================================== 🎉 构建完成 🎉 =========================================="
echo ""
diff --git a/scripts/14-config-power-key.sh b/scripts/14-config-power-key.sh
new file mode 100644
index 0000000..2c10c5b
--- /dev/null
+++ b/scripts/14-config-power-key.sh
@@ -0,0 +1,345 @@
+#!/bin/bash
+set -e
+
+if [ "$DESKTOP_ENV" != "gnome" ]; then
+ echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] ⏭️ 非 GNOME 桌面,跳过电源键配置"
+ exit 0
+fi
+
+echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] 🔘 配置电源键(短按熄屏 / 长按 3s GNOME 关机菜单)"
+
+echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] └─ 禁用 systemd 电源键行为"
+install -d rootdir/etc/systemd/logind.conf.d
+cat > rootdir/etc/systemd/logind.conf.d/raphael-power-key.conf << 'EOF'
+[Login]
+HandlePowerKey=ignore
+HandlePowerKeyLongPress=ignore
+PowerKeyIgnoreInhibited=yes
+EOF
+
+echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] └─ 安装电源键守护进程"
+install -d rootdir/usr/local/sbin
+cat > rootdir/usr/local/sbin/raphael-power-key-wait.sh << 'WEOF'
+#!/bin/sh
+USER_NAME="${USER_NAME:-user}"
+RUN_UID=$(id -u "$USER_NAME" 2>/dev/null) || exit 1
+RUN="/run/user/$RUN_UID"
+for i in $(seq 1 120); do
+ if [ -S "$RUN/bus" ] && pgrep -u "$USER_NAME" -x gnome-shell >/dev/null 2>&1; then
+ sleep 3
+ exit 0
+ fi
+ sleep 1
+done
+echo "raphael-power-key-wait: timeout waiting for $USER_NAME session" >&2
+exit 1
+WEOF
+chmod 755 rootdir/usr/local/sbin/raphael-power-key-wait.sh
+
+cat > rootdir/usr/local/sbin/raphael-power-key.py << 'PYEOF'
+#!/usr/bin/env python3
+import fcntl
+import logging
+import os
+import pwd
+import select
+import struct
+import subprocess
+import sys
+import threading
+import time
+from pathlib import Path
+
+EV_KEY = 0x01
+KEY_POWER = 116
+EVENT_FMT = "llHHi"
+EVENT_SIZE = struct.calcsize(EVENT_FMT)
+LONG_PRESS_SEC = 3.0
+USER_NAME = os.environ.get("USER_NAME", "user")
+
+MUTTER_BUS = "org.gnome.Mutter.DisplayConfig"
+MUTTER_PATH = "/org/gnome/Mutter/DisplayConfig"
+MUTTER_IFACE = "org.gnome.Mutter.DisplayConfig"
+POWER_PROP = "PowerSaveMode"
+
+logging.basicConfig(
+ level=logging.INFO,
+ format="raphael-power-key: %(message)s",
+ stream=sys.stdout,
+)
+log = logging.getLogger("raphael-power-key")
+
+
+def find_power_input():
+ base = Path("/sys/class/input")
+ for name_path in sorted(base.glob("input*/name")):
+ name = name_path.read_text().strip()
+ if name == "pm8941_pwrkey":
+ num = name_path.parent.name.replace("input", "")
+ dev = Path(f"/dev/input/event{num}")
+ if dev.exists():
+ return dev
+ return Path("/dev/input/event0")
+
+
+def user_env():
+ uid = pwd.getpwnam(USER_NAME).pw_uid
+ runtime = Path(f"/run/user/{uid}")
+ env = os.environ.copy()
+ env.update({
+ "HOME": f"/home/{USER_NAME}",
+ "USER": USER_NAME,
+ "LOGNAME": USER_NAME,
+ "XDG_RUNTIME_DIR": str(runtime),
+ "DBUS_SESSION_BUS_ADDRESS": f"unix:path={runtime / 'bus'}",
+ })
+ for disp in ("wayland-0", "wayland-1"):
+ if (runtime / disp).exists():
+ env["WAYLAND_DISPLAY"] = disp
+ break
+ return env
+
+
+def run_as_user(args):
+ env = user_env()
+ env_cmd = [
+ "env",
+ f"HOME={env['HOME']}",
+ f"USER={env['USER']}",
+ f"LOGNAME={env['LOGNAME']}",
+ f"XDG_RUNTIME_DIR={env['XDG_RUNTIME_DIR']}",
+ f"DBUS_SESSION_BUS_ADDRESS={env['DBUS_SESSION_BUS_ADDRESS']}",
+ ]
+ if "WAYLAND_DISPLAY" in env:
+ env_cmd.append(f"WAYLAND_DISPLAY={env['WAYLAND_DISPLAY']}")
+ return subprocess.run(
+ ["runuser", "-u", USER_NAME, "--", *env_cmd, *args],
+ check=False,
+ capture_output=True,
+ text=True,
+ )
+
+
+def get_power_save_mode():
+ r = run_as_user(
+ ["busctl", "--user", "get-property",
+ MUTTER_BUS, MUTTER_PATH, MUTTER_IFACE, POWER_PROP]
+ )
+ if r.returncode != 0:
+ log.warning("get PowerSaveMode failed: %s", r.stderr.strip())
+ return 0
+ return int(r.stdout.split()[1])
+
+
+def set_power_save_mode(mode):
+ r = run_as_user(
+ ["busctl", "--user", "set-property",
+ MUTTER_BUS, MUTTER_PATH, MUTTER_IFACE, POWER_PROP, "i", str(mode)]
+ )
+ if r.returncode != 0:
+ log.warning("set PowerSaveMode failed: %s", r.stderr.strip())
+ return False
+ return True
+
+
+def toggle_screen():
+ try:
+ current = get_power_save_mode()
+ target = 0 if current else 1
+ log.info("toggle screen PowerSaveMode %s -> %s", current, target)
+ set_power_save_mode(target)
+ except Exception as exc:
+ log.error("toggle_screen failed: %s", exc)
+
+
+def show_shutdown_dialog():
+ log.info("show GNOME native shutdown dialog")
+ r = run_as_user(
+ ["busctl", "--user", "call",
+ "org.gnome.SessionManager",
+ "/org/gnome/SessionManager",
+ "org.gnome.SessionManager",
+ "RequestShutdown"]
+ )
+ if r.returncode != 0:
+ log.warning("RequestShutdown failed: %s", r.stderr.strip())
+ run_as_user(["gnome-session-quit", "--power-off"])
+
+
+def session_ready():
+ uid = pwd.getpwnam(USER_NAME).pw_uid
+ runtime = Path(f"/run/user/{uid}")
+ bus = runtime / "bus"
+ if not bus.exists():
+ return False
+ try:
+ subprocess.run(
+ ["pgrep", "-u", USER_NAME, "-x", "gnome-shell"],
+ check=True,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+ return True
+ except subprocess.CalledProcessError:
+ return False
+
+
+def wait_for_session(timeout=120):
+ log.info("waiting for %s GNOME session", USER_NAME)
+ deadline = time.monotonic() + timeout
+ while time.monotonic() < deadline:
+ if session_ready():
+ time.sleep(3)
+ log.info("session ready")
+ return True
+ time.sleep(1)
+ log.error("session not ready after %ss", timeout)
+ return False
+
+
+def grab_device(fd):
+ EVIOCGRAB = 0x40044590
+ try:
+ fcntl.ioctl(fd, EVIOCGRAB, 1)
+ return True
+ except OSError as exc:
+ log.warning("EVIOCGRAB failed: %s", exc)
+ return False
+
+
+def main():
+ if not wait_for_session():
+ sys.exit(1)
+
+ dev = find_power_input()
+ fd = os.open(str(dev), os.O_RDONLY | os.O_NONBLOCK)
+ grabbed = grab_device(fd)
+ if grabbed:
+ log.info("grabbed input device")
+ else:
+ log.warning("initial grab failed, will retry")
+ log.info("listening on %s", dev)
+
+ press_time = None
+ long_fired = False
+ long_timer = None
+ is_pressed = False
+ last_grab_try = time.monotonic()
+
+ def cancel_long_timer():
+ nonlocal long_timer
+ if long_timer is not None:
+ long_timer.cancel()
+ long_timer = None
+
+ def on_long_press():
+ nonlocal long_fired
+ if not is_pressed:
+ return
+ long_fired = True
+ show_shutdown_dialog()
+
+ while True:
+ r, _, _ = select.select([fd], [], [], 1.0)
+ now = time.monotonic()
+ if not grabbed and now - last_grab_try >= 5:
+ last_grab_try = now
+ if grab_device(fd):
+ grabbed = True
+ log.info("grabbed input device (retry)")
+ if not r:
+ continue
+ data = os.read(fd, EVENT_SIZE)
+ if len(data) < EVENT_SIZE:
+ continue
+ _sec, _usec, ev_type, code, value = struct.unpack(EVENT_FMT, data)
+ if ev_type != EV_KEY or code != KEY_POWER:
+ continue
+
+ log.info("KEY_POWER value=%s", value)
+
+ if value == 1:
+ if not is_pressed:
+ is_pressed = True
+ press_time = time.monotonic()
+ long_fired = False
+ cancel_long_timer()
+ long_timer = threading.Timer(LONG_PRESS_SEC, on_long_press)
+ long_timer.daemon = True
+ long_timer.start()
+ elif value == 0 and press_time is not None:
+ is_pressed = False
+ cancel_long_timer()
+ if not long_fired:
+ duration = time.monotonic() - press_time
+ if duration < LONG_PRESS_SEC:
+ toggle_screen()
+ press_time = None
+
+
+if __name__ == "__main__":
+ main()
+PYEOF
+chmod 755 rootdir/usr/local/sbin/raphael-power-key.py
+
+echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] └─ 创建 systemd 服务"
+cat > rootdir/etc/systemd/system/raphael-power-key.service << 'EOF'
+[Unit]
+Description=Raphael power key handler (screen toggle / shutdown menu)
+After=gdm.service network.target
+Wants=gdm.service
+
+[Service]
+Type=simple
+ExecStartPre=/usr/local/sbin/raphael-power-key-wait.sh
+ExecStart=/usr/bin/python3 /usr/local/sbin/raphael-power-key.py
+Restart=on-failure
+RestartSec=5
+TimeoutStopSec=5
+KillMode=mixed
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
+cat > rootdir/etc/systemd/system/raphael-power-key-restart.service << 'EOF'
+[Unit]
+Description=Restart Raphael power key handler after desktop is up
+After=gdm.service
+
+[Service]
+Type=oneshot
+ExecStart=/bin/systemctl restart raphael-power-key.service
+EOF
+
+cat > rootdir/etc/systemd/system/raphael-power-key-restart.timer << 'EOF'
+[Unit]
+Description=Delayed restart of Raphael power key handler
+
+[Timer]
+OnBootSec=45s
+Unit=raphael-power-key-restart.service
+
+[Install]
+WantedBy=timers.target
+EOF
+
+echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] └─ 启用服务"
+chroot rootdir systemctl enable raphael-power-key.service
+chroot rootdir systemctl enable raphael-power-key-restart.timer
+
+echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] └─ 禁用 GNOME 自带电源键处理"
+install -d rootdir/etc/dconf/db/local.d rootdir/etc/dconf/profile
+cat > rootdir/etc/dconf/db/local.d/01-power-key << 'EOF'
+[org/gnome/settings-daemon/plugins/power]
+power-button-action='nothing'
+EOF
+if [ ! -f rootdir/etc/dconf/profile/user ]; then
+ cat > rootdir/etc/dconf/profile/user << 'EOF'
+user-db:user
+system-db:local
+EOF
+fi
+chroot rootdir dconf update 2>/dev/null || true
+
+echo "[$(date +'%Y-%m-%d %H:%M:%S')] [14] ✅ 电源键配置完成"
diff --git a/scripts/14-config-zram.sh b/scripts/15-config-zram.sh
similarity index 100%
rename from scripts/14-config-zram.sh
rename to scripts/15-config-zram.sh
diff --git a/scripts/15-config-audio.sh b/scripts/16-config-audio.sh
similarity index 100%
rename from scripts/15-config-audio.sh
rename to scripts/16-config-audio.sh
diff --git a/scripts/16-cleanup.sh b/scripts/17-cleanup.sh
similarity index 100%
rename from scripts/16-cleanup.sh
rename to scripts/17-cleanup.sh
diff --git a/scripts/17-finalize.sh b/scripts/18-finalize.sh
similarity index 100%
rename from scripts/17-finalize.sh
rename to scripts/18-finalize.sh