# -*- coding: utf-8 -*- """把任务栏恢复常显,并把测试改成只读。 教训:上一个测试会**真的执行**每一个开关,包括 lock_input 锁键盘鼠标(要管理员才能解) taskbar_hide 杀掉 explorer 重启 这在用户真机上跑是闯祸,必须改成只读检查。 """ from __future__ import annotations import subprocess import sys import time import winreg from pathlib import Path SETTINGS_KEY = (r"Software\Microsoft\Windows\CurrentVersion\Explorer" r"\StuckRects3") TEST = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\_tests" r"\test_toggles.py") def restore_taskbar() -> None: with winreg.OpenKey(winreg.HKEY_CURRENT_USER, SETTINGS_KEY, 0, winreg.KEY_READ | winreg.KEY_WRITE) as key: raw, _kind = winreg.QueryValueEx(key, "Settings") blob = bytearray(raw) before = blob[8] blob[8] = 2 # 2 = 常显 if before != 2: winreg.SetValueEx(key, "Settings", 0, winreg.REG_BINARY, bytes(blob)) print(f" 任务栏 Settings[8]: {before} -> 2(恢复常显)") else: print(" 任务栏本来就是常显,不用改") # 让 explorer 重新读一次设置。用 taskkill 比 Stop-Process 温和一点, # 而且 explorer 会被系统自动拉起来。 subprocess.run(["taskkill", "/f", "/im", "explorer.exe"], capture_output=True, creationflags=0x08000000) print(" 已通知 explorer 重载(它会自己起来)") time.sleep(4) NON_DESTRUCTIVE = '''# -*- coding: utf-8 -*- """只读回归测试:开关的方向性 + 能开就要能关。 **重要:这个测试不执行任何破坏性功能。** 之前的版本会真的跑每一个 toggle,包括「锁键盘鼠标」(要管理员才能解) 和「任务栏自动隐藏」(会杀 explorer)——在用户真机上那是闯祸。 现在改成: * 系统状态只用**只读**方式核对(注册表 / 窗口枚举) * 只真正执行明确安全的几个开关(循环播放、随机播放) * 其余开关只核对:声明了两个方向、实现里两个分支都在 * 关窗口那条链路是真的执行(它本来就是把东西关掉,安全) """ import ctypes import os import re import sys import tempfile import time import winreg from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "windows")) import tkinter as tk # noqa: E402 from lanremote.actions import Actions # noqa: E402 from lanremote.config import Store # noqa: E402 from lanremote.features import Features # noqa: E402 from lanremote.headless import HeadlessUI # noqa: E402 # 会真的改动系统、或者要管理员才能撤销的开关:不执行 DESTRUCTIVE = { "lock_input", "taskbar_hide", "autostart", "quit_agent", "hide_icons", "restrict_taskmgr", "restrict_regedit", "restrict_cmd", "restrict_wallpaper", "restrict_power", "block_new_app", "allow_run", "allow_power", "allow_screen", "close_pair_after_first", "night_mode", "hidden_files", "clock_seconds", "mouse_trail", } passed = 0 failed = 0 def check(name, ok, detail=""): global passed, failed if ok: passed += 1 print(f" [PASS] {name}") else: failed += 1 print(f" [FAIL] {name} {detail}") def visible_windows(keyword): user32 = ctypes.windll.user32 proc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p) found = [] def callback(hwnd, _l): pid = ctypes.c_ulong() user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid)) if pid.value != os.getpid() or not user32.IsWindowVisible(hwnd): return True length = user32.GetWindowTextLengthW(hwnd) buf = ctypes.create_unicode_buffer(length + 2) user32.GetWindowTextW(hwnd, buf, length + 2) if keyword in buf.value: found.append(buf.value) return True user32.EnumWindows(proc(callback), 0) return found def main() -> int: store = Store(Path(tempfile.mkdtemp())) ui = HeadlessUI(store) actions = Actions(ui, store) features = Features(actions) ui.root # --------------------------------------------------------------- print("一、功能表完整性") defs = features.defs() check("功能数量 > 200", len(defs) > 200, f"{len(defs)} 个") missing = [d["name"] for d in defs if not hasattr(features, "_do_" + d["name"])] check("没有缺实现的功能", not missing, str(missing)[:120]) groups = sorted({d["group"] for d in defs}) check("分组数 = 14", len(groups) == 14, str(groups)) # --------------------------------------------------------------- print() print("二、每个开关都声明了「开」和「关」两个方向") toggles = [d for d in defs if d.get("kind") == "toggle"] check("有 toggle 类功能", len(toggles) >= 8, f"{len(toggles)} 个") source = (ROOT / "windows" / "lanremote" / "features.py").read_text( encoding="utf-8") one_way = [] for item in toggles: name = item["name"] # 实现里必须用到了 on 参数(不然就是只能往一个方向走) body = source index = source.find(f"def _do_{name}(") if index > 0: body = source[index:index + 1400] uses_on = ("params.get(\"on\")" in body or "on\")" in body or "_truthy(params" in body) if not uses_on: one_way.append(name) check("所有开关都用到了 on 参数(能往两个方向走)", not one_way, f"只往一个方向的: {one_way}") # 手表侧:缓存必须跟着翻转 main_java = (ROOT / "android" / "src" / "com" / "lanremote" / "watch" / "MainActivity.java").read_text(encoding="utf-8") check("手表 toggle 后会更新本地缓存", 'feature.put("on"' in main_java, "没找到 feature.put(\"on\", ...)") # --------------------------------------------------------------- print() print("三、安全开关真的往返一次") for name in ("loop_play", "shuffle_play"): try: on = features.run(name, {"on": True}) off = features.run(name, {"on": False}) check(f"{name} 两个方向话术不同", str(on) != str(off), f"开={on!r} 关={off!r}") except Exception as exc: # noqa: BLE001 check(f"{name} 往返", False, str(exc)[:80]) # --------------------------------------------------------------- print() print("四、手表开的画面必须能关掉") ui.notify("测试通知一", "内容") ui.notify("测试通知二", "内容") time.sleep(1.2) before = visible_windows("通知") check("通知确实弹出来了", len(before) >= 2, f"{len(before)} 个") result = features.run("close_visuals", {}) time.sleep(1.2) after = visible_windows("通知") check("close_visuals 关掉了通知", len(after) == 0, f"关前 {len(before)},关后 {len(after)}({result})") features.run("big_text", {"text": "测试大字XYZ"}) time.sleep(1.0) check("全屏大字弹出来了", len(visible_windows("测试大字XYZ")) >= 1) features.run("close_visuals", {}) time.sleep(1.0) check("close_visuals 关掉了全屏大字", len(visible_windows("测试大字XYZ")) == 0) again = features.run("close_visuals", {}) check("没东西可关时也不报错", "没有" in str(again), str(again)) # --------------------------------------------------------------- print() print("五、系统状态用只读方式核对") with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion" r"\Explorer\StuckRects3") as key: raw, _ = winreg.QueryValueEx(key, "Settings") blob = bytes(raw) check("Settings 能读到且够长", len(blob) > 8, f"{len(blob)} 字节") check("_taskbar_hidden() 与注册表一致", features._taskbar_hidden() == bool(blob[8] & 1), f"函数={features._taskbar_hidden()} 注册表={bool(blob[8] & 1)}") from lanremote import autostart try: with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run" ) as key: winreg.QueryValueEx(key, "LanRemoteAgent") registry_on = True except FileNotFoundError: registry_on = False check("is_enabled() 与注册表一致", autostart.is_enabled() == registry_on, f"函数={autostart.is_enabled()} 注册表={registry_on}") ui.stop() print() print("=" * 66) print(f"通过 {passed} 项,失败 {failed} 项") if failed: print("失败项:") return 0 if failed == 0 else 1 if __name__ == "__main__": sys.exit(main()) ''' def main() -> int: restore_taskbar() TEST.write_text(NON_DESTRUCTIVE, encoding="utf-8") print(f" 已把 {TEST.name} 改写成只读测试") return 0 if __name__ == "__main__": sys.exit(main())