2.3.0:手表界面精简 + 播放器 + 鼠标重做

手表端
- 功能页从 10 个杂项精简到 7 个(屏幕/鼠标/媒体/文件/电脑/语音/电源)
- 删掉:游戏封锁、待办、掷骰子、抽奖、壁纸、显示器开关、定时关机、
  剪贴板历史、性能/磁盘/电量、文件夹浏览、教室限制等
- 改成显式列按钮,不再把电脑端所有功能组无脑铺到表盘
- 远程鼠标控制重做:滑动区 + 左键/滚轮/右键三按钮
  滚轮点按=中键、上下滑=滚动
- 新增视频/音乐播放器(手表本地播放):进度拖动、左右滑快进退10秒、
  点画面播放暂停、上一/下一、播完自动下一首

电脑端
- 新增 kill_all(结束所有进程),白名单保护系统关键进程和自身
- 新增 media_list / media_pull(播放器数据源)
  安全边界:只允许媒体目录,用 relative_to 判断,防同前缀兄弟目录绕过

中转站
- known_devices 从 ID 集合改成「设备ID -> 配对码」映射
- 修复:管理员改码后关机超过 6 小时,改码会被超时清理冲掉
- 老格式 state 文件平滑升级
This commit is contained in:
xmz7891
2026-10-18 11:39:14 +08:00
parent 1d368979aa
commit 2061f9525f
50 changed files with 13812 additions and 584 deletions
+90
View File
@@ -390,6 +390,7 @@ class Features:
add("site_list", "看屏蔽列表", "action", "教室")
add("site_clear", "清空屏蔽列表", "action", "教室")
add("kill_games", "结束游戏进程", "action", "教室")
add("kill_all", "结束所有进程", "action", "系统")
add("kill_by_name", "按名字结束进程", "input", "教室",
hint="进程名,如 game.exe", key="name")
add("bell", "下课铃", "action", "教室")
@@ -2978,6 +2979,95 @@ class Features:
raise ValueError("进程名为空")
return self.actions.kill_process(0, name)
# ---------------- 一键结束所有进程(2.3.0)----------------
#
# 用户要求「一键结束所有进程」。这个操作很危险,所以做了**白名单保护**:
# * 本程序自己的 PID 和父进程链(杀了就再也连不上)
# * 系统关键进程(杀了会蓝屏/注销/桌面消失)
# 其余全杀。
# 绝对不能结束的进程名(小写)。
#
# 这些名字都是踩过坑或者有明确后果的:
# csrss / wininit / winlogon / services / lsass / smss -> 蓝屏或立即重启
# svchost -> 一杀就掉一片服务(网络、音频、打印全没)
# dwm -> 窗口全部失��重绘
# explorer -> 桌面和任务栏消失(虽然会自动重启,但用户会以为坏了)
# audiodg -> 音频引擎
# ykxmz / python / pythonw -> 本程序
PROTECTED_NAMES = {
"system", "system idle process", "registry", "memory compression",
"smss.exe", "csrss.exe", "wininit.exe", "winlogon.exe", "services.exe",
"lsass.exe", "lsm.exe", "svchost.exe", "dwm.exe", "fontdrvhost.exe",
"sihost.exe", "ctfmon.exe", "audiodg.exe", "spoolsv.exe",
"explorer.exe", "taskhost.exe", "taskhostw.exe", "runtimebroker.exe",
"searchindexer.exe", "wmiprvse.exe", "dllhost.exe", "conhost.exe",
"ykxmz.exe", "python.exe", "pythonw.exe", "cmd.exe", "taskkill.exe",
}
def _protected_pids(self) -> set:
"""自己和父进程链的 PID —— 这些杀了等于自断后路。"""
import os
import subprocess as _sp
pids = {os.getpid()}
pid = os.getpid()
for _ in range(6): # 往上追几层就够了
try:
out = _sp.run(
["wmic", "process", "where", "ProcessId=%d" % pid,
"get", "ParentProcessId", "/value"],
capture_output=True, timeout=10,
creationflags=getattr(_sp, "CREATE_NO_WINDOW", 0),
encoding="mbcs", errors="replace").stdout or ""
parent = 0
for line in out.splitlines():
if "=" in line and "ParentProcessId" in line:
try:
parent = int(line.split("=")[-1].strip())
except ValueError:
parent = 0
if parent <= 0 or parent in pids:
break
pids.add(parent)
pid = parent
except Exception: # noqa: BLE001
break
return pids
def _do_kill_all(self, params) -> str:
import os
me = os.getpid()
guard = set(self.PROTECTED_NAMES)
for proc in self.actions.list_processes(limit=3):
pass
protected_pids = self._protected_pids()
killed = []
skipped = 0
failed = 0
for proc in self.actions.list_processes(limit=500):
name = (proc.get("name") or "").strip()
low = name.lower()
pid = int(proc.get("pid") or 0)
if pid <= 0 or pid == me or pid in protected_pids:
skipped += 1
continue
if low in guard:
skipped += 1
continue
try:
self.actions.kill_process(pid)
killed.append(name)
except Exception: # noqa: BLE001
failed += 1
if not killed:
return "没有可结束的程序(系统和本程序都已排除)"
head = "、".join(killed[:8])
more = "" if len(killed) <= 8 else ("… 等 %d 个" % len(killed))
return ("已结束 %d 个程序:%s%s(跳过系统进程 %d 个,失败 %d 个)"
% (len(killed), head, more, skipped, failed))
# ---------------- 课堂 ----------------
def _do_bell(self, params) -> str: