# -*- coding: utf-8 -*- """验证「电脑本地剪贴板变化 -> 推送给客户端」。 **安全说明**:只用 PowerShell 的 Set-Clipboard,绝不用 ctypes 写剪贴板。 上一版用 ctypes 时 GlobalAlloc 返回的 64 位句柄被 ctypes 按 32 位 int 截断,SetClipboardData 拿着坏句柄把系统剪贴板搞成"被占用", 连 PowerShell 都用不了 —— 那个脚本已经删掉了。 """ from __future__ import annotations import json import shutil import socket import subprocess import sys import time from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") EXE = ROOT / "dist_exe" / "ykxmz" / "ykxmz.exe" PORT = 8843 NO_WINDOW = 0x08000000 def set_clipboard(text: str) -> bool: """用 PowerShell 设剪贴板,并等它真的完成。""" proc = subprocess.run( ["powershell", "-NoProfile", "-Command", f"Set-Clipboard -Value '{text}'"], capture_output=True, creationflags=NO_WINDOW, timeout=20) return proc.returncode == 0 def get_clipboard() -> str: proc = subprocess.run( ["powershell", "-NoProfile", "-Command", "Get-Clipboard -Raw"], capture_output=True, creationflags=NO_WINDOW, timeout=20) return (proc.stdout or b"").decode("utf-8", "replace").strip() def main() -> int: d = EXE.parent real = d / "data" bak = None if real.exists(): bak = d / "data_bk_cp2" if bak.exists(): shutil.rmtree(bak, ignore_errors=True) shutil.move(str(real), str(bak)) proc = None try: proc = subprocess.Popen( [str(EXE), "--port", str(PORT), "--add-device", "10"], cwd=str(d), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) code = "" for _ in range(40): time.sleep(0.5) try: code = json.loads((d / "data" / "settings.json").read_text( encoding="utf-8")).get("pairing_code", "") except Exception: # noqa: BLE001 code = "" if code: try: probe = socket.create_connection(("127.0.0.1", PORT), timeout=1) probe.close() break except OSError: continue sock = socket.create_connection(("127.0.0.1", PORT), timeout=15) sock.settimeout(3) buf = b"" def send(obj): sock.sendall((json.dumps(obj, ensure_ascii=False) + "\n").encode()) def read(timeout=3): nonlocal buf deadline = time.time() + timeout while True: while b"\n" not in buf: if time.time() > deadline: return None try: chunk = sock.recv(65536) except (TimeoutError, OSError): return None if not chunk: return None buf += chunk line, _, buf = buf.partition(b"\n") try: return json.loads(line.decode("utf-8")) except Exception: # noqa: BLE001 continue send({"cmd": "pair", "deviceId": "cp", "deviceName": "cp", "code": code}) read(timeout=10) print(" 已配对") send({"cmd": "clip_get"}) print(" 服务端读到的剪贴板: " + str(read(timeout=10))) text = "本地改动-" + str(int(time.time())) print(" 用 PowerShell 写入: " + text) ok = set_clipboard(text) print(" 写入成功: " + str(ok)) print(" PowerShell 读回: " + get_clipboard()) # 等服务端推送 print(" 等推送…") got = None deadline = time.time() + 20 while time.time() < deadline: message = read(timeout=2) if message is None: continue if message.get("event") == "clip": got = message break if got: print(" ✓ 收到推送: " + str(got)[:100]) else: print(" ✗ 20 秒内没收到 clip 推送") sock.close() return 0 if got else 1 finally: if proc: try: proc.terminate() proc.wait(timeout=8) except Exception: # noqa: BLE001 try: proc.kill() except Exception: # noqa: BLE001 pass time.sleep(1) if real.exists(): shutil.rmtree(real, ignore_errors=True) if bak and bak.exists(): shutil.move(str(bak), str(real)) if __name__ == "__main__": sys.exit(main())