#!/usr/bin/env python3 """Controlled existing-stream POC; always restores the remote-video cursor toggle. Only run with cursor-poc-host.ps1's disposable foreground window on Windows. Shape selections here are scripted replay, NOT automatic host synchronization. """ import importlib.util import json import os from pathlib import Path import signal import subprocess as S import time ROOT = Path(__file__).resolve().parent os.environ.update(DISPLAY=":0", XAUTHORITY="/home/armbian/.Xauthority") spec = importlib.util.spec_from_file_location("cursor_poc", ROOT / "cursor-poc-x11.py") m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m) OUT = ROOT / "cursor-poc-evidence-v3" OUT.mkdir(exist_ok=False) # Never overwrite earlier evidence. def xd(*args): return S.check_output(["xdotool", *map(str,args)], text=True).strip() pid = int(xd("getwindowfocus", "getwindowpid")) window = int(xd("getwindowfocus")) cmd = Path(f"/proc/{pid}/cmdline").read_bytes().replace(b"\0", b" ") if b"/moonlight " not in cmd or b" stream 192.168.1.70 Desktop " not in cmd or b" --absolute-mouse " not in cmd: raise RuntimeError("Unexpected foreground process") assets = m.validate_assets(m.read_json(ROOT / "windows-shapes.json", 4*1024*1024)) cursor = m.LocalCursor(window) if any(cursor.snapshot()["argb"]): cursor.close(); raise RuntimeError("Original local cursor is not hidden") hidden_remote = False paused = False records = [] def interrupted(signum, frame): raise SystemExit(128+signum) signal.signal(signal.SIGTERM, interrupted) signal.signal(signal.SIGINT, interrupted) def focus(): if int(xd("getwindowfocus", "getwindowpid")) != pid: raise RuntimeError("Moonlight lost foreground; stop the POC") def capture(name): with (OUT / (name+".xwd")).open("wb") as f: S.run(["xwd", "-root", "-silent"], stdout=f, check=True) try: cursor.cursors = {k: cursor.create(v) for k,v in assets.items()} cursor.cursors["__hidden"] = cursor.create(dict(width=1,height=1,hotX=0,hotY=0,argb=[0])) focus(); xd("mousemove", 320, 500); time.sleep(.8) capture("01-remote-cursor") focus(); xd("key", "ctrl+alt+shift+n"); hidden_remote=True xd("mousemove",321,500); time.sleep(1.0) capture("02-video-cursor-disabled") for name,x in (("arrow",320),("ibeam",960),("sizewe",1600),("wait",2240),("__hidden",320)): focus(); y=1250 if name=="__hidden" else 500 xd("mousemove", x,y); time.sleep(.25) cursor.apply(cursor.cursors[name]); time.sleep(.05) snap=cursor.snapshot() (OUT/(name+".json")).write_text(json.dumps(snap)) if name=="__hidden": assert not any(snap["argb"]), "Hidden cursor still has visible pixels" else: a=assets[name] assert (snap["width"],snap["height"],snap["hotX"],snap["hotY"]) == (a["width"],a["height"],a["hotX"],a["hotY"]) assert any(snap["argb"]), "Visible cursor has no pixels" assert (snap["x"],snap["y"])==(x,y) records.append(dict(shape=name,x=x,y=y,visible=any(snap["argb"]))) time.sleep(.3) # Allow the host probe to observe the real shape/visibility. focus(); xd("mousemove",320,500); cursor.apply(cursor.cursors["arrow"]); time.sleep(.4) # Freeze only this client for < 0.5s; X11 cursor must move while its video/input # event processing is stopped. SIGCONT is guaranteed before cursor restoration. os.kill(pid,signal.SIGSTOP); paused=True try: first=cursor.snapshot() xd("mousemove",500,650); time.sleep(.12) second=cursor.snapshot() assert (second["x"],second["y"])==(500,650) assert first["argb"]==second["argb"] records.append(dict(test="client-paused-local-motion",before=[first["x"],first["y"]],after=[second["x"],second["y"]],passed=True)) finally: os.kill(pid,signal.SIGCONT); paused=False time.sleep(.5) # Click only within the disposable Windows form. Scripted shape replay is # deliberately distinct from the not-yet-implemented live cursor protocol. for i in range(32): focus(); n=i%4; x=320+640*n; y=600+(i//4)*20 cursor.apply(cursor.cursors[("arrow","ibeam","sizewe","wait")[n]]) xd("mousemove",x,y); time.sleep(.06); xd("click",1); time.sleep(.06) capture("03-local-mode-video-only") # Verify the actual helper's lease failure path while video cursor is hidden. cursor.apply(cursor.original) lease=OUT/"lease.json" lease.write_text(json.dumps(dict(version=1,shape="arrow",visible=True,expires=time.time()+.8))) result=S.run(["python3",str(ROOT/"cursor-poc-x11.py"),"--window",str(window),"--pid",str(pid), "--assets",str(ROOT/"windows-shapes.json"),"--state",str(lease),"--seconds","3"], capture_output=True,text=True,timeout=5) (OUT/"lease-expiry.log").write_text(result.stdout+result.stderr) assert result.returncode==0 and "lease-ended" in result.stdout and "sdl-hidden-cursor-restored" in result.stdout # Xorg can briefly have no current cursor image after another connection's # final cursor resource is released. Trigger pointer recomputation before # checking the *post-exit* image; do not mistake this for an alpha image. xd("mousemove",2240,741); time.sleep(.1) assert not any(cursor.snapshot()["argb"]) records.append(dict(test="helper-lease-expiry",passed=True)) finally: if paused: os.kill(pid,signal.SIGCONT) try: cursor.close(sdl_pid=pid) finally: # Remote restoration must still run when local cleanup raises an error. if hidden_remote: xd("windowactivate","--sync",window); focus() xd("key","ctrl+alt+shift+n"); time.sleep(.8) capture("04-remote-cursor-restored") (OUT/"results.json").write_text(json.dumps(records,indent=2)) print(json.dumps(dict(restored_remote_cursor=hidden_remote,records=records)),flush=True)